Add legacy data import feature
authorbsinou <bsinou@argeo.org>
Fri, 3 Mar 2017 16:49:14 +0000 (17:49 +0100)
committerbsinou <bsinou@argeo.org>
Fri, 3 Mar 2017 16:49:14 +0000 (17:49 +0100)
org.argeo.suite.app/META-INF/spring/ui-people.xml
org.argeo.suite.workbench.rap/META-INF/spring/parts.xml
org.argeo.suite.workbench.rap/plugin.xml
org.argeo.suite.workbench.rap/src/org/argeo/suite/workbench/commands/ImportEntities.java [new file with mode: 0644]
org.argeo.suite.workbench.rap/theme/argeo-classic/icons/more.gif [new file with mode: 0644]
org.argeo.suite.workbench.rap/theme/argeo-classic/icons/upload.gif [new file with mode: 0644]

index e2c608197dbb1345d465c1560458e1bbb8c6b8be..aa358672c2186443f4b5c01f763020597f81d3bd 100644 (file)
        <!-- Tag like properties -->
        <bean id="tagsPart" class="org.argeo.people.web.parts.TagLikeValuesPart">
                <property name="propertyName">
-                       <util:constant static-field="org.argeo.connect.ConnectNames.CONNECT_TAGS" />
+                       <util:constant static-field="org.argeo.connect.resources.ResourcesNames.CONNECT_TAGS" />
                </property>
        </bean>
        <bean id="mailingListsPart" class="org.argeo.people.web.parts.TagLikeValuesPart">
index efa448242ceaec8dac7829c58d72df0078bb2e90..40b1997a958fb8888c194bf77074d5dd7c3cad91 100644 (file)
@@ -7,11 +7,12 @@
 
        <!-- COMMANDS -->
 
-<!--   <bean id="openEntityEditor" class="org.argeo.suite.workbench.commands.OpenEntityEditor" -->
-<!--           scope="prototype"> -->
-<!--           <property name="repository" ref="repository" /> -->
-<!--           <property name="appWorkbenchService" ref="appWorkbenchService" /> -->
-<!--   </bean> -->
+       <bean id="importEntities" class="org.argeo.suite.workbench.commands.ImportEntities"
+               scope="prototype">
+               <property name="repository" ref="repository" />
+               <property name="resourcesService" ref="resourcesService" />
+               <property name="peopleService" ref="peopleService" />
+       </bean>
 
        <!-- VIEWS -->
        
index d4550c78103807b69d012a53d26ea5827429ddb3..20ea41cba73378defcd93e985980e4417d10cc00 100644 (file)
        <!-- COMMANDS -->       
        <extension
          point="org.eclipse.ui.commands">
+               <command
+               id="org.argeo.suite.workbench.rap.importEntities"
+                       defaultHandler="org.argeo.eclipse.spring.SpringExtensionFactory"
+            name="Import entities">
+       </command>      
        </extension>
 
        <!-- MENU CONTRIBUTION --> 
        <extension
                id="menu:org.eclipse.ui.main.menu"
                point="org.eclipse.ui.menus">
+               
+               <menuContribution locationURI="menu:org.argeo.cms.ui.workbench.rap.mainMenu?before=org.argeo.cms.ui.workbench.rap.beforeExit">
+                       <menu
+                               id="org.argeo.suite.workbench.rap.advancedMenu"
+                               label="Administration"
+                               icon="theme/argeo-classic/icons/more.gif"
+                               tooltip="Access to advanced commands">
+                               <visibleWhen
+                               checkEnabled="false">
+                               <with variable="roles">
+                                       <iterate ifEmpty="false" operator="or">
+                                               <equals value="cn=org.argeo.suite.manager,ou=roles,ou=node" />
+                                       </iterate>
+                               </with>
+                               </visibleWhen>
+              </menu>
+               </menuContribution>
+               <menuContribution locationURI="menu:org.argeo.suite.workbench.rap.advancedMenu">
+               <command
+                       commandId="org.argeo.suite.workbench.rap.importEntities"
+                               icon="theme/argeo-classic/icons/upload.gif"
+                               label="Import data..."
+                               tooltip="Upload XLS file that contains legacy/external data">
+                       </command>
+               </menuContribution>
        </extension>
        
        <!-- BRANDING AND THEMES -->
diff --git a/org.argeo.suite.workbench.rap/src/org/argeo/suite/workbench/commands/ImportEntities.java b/org.argeo.suite.workbench.rap/src/org/argeo/suite/workbench/commands/ImportEntities.java
new file mode 100644 (file)
index 0000000..a267df5
--- /dev/null
@@ -0,0 +1,493 @@
+package org.argeo.suite.workbench.commands;
+
+import static org.argeo.connect.util.JxlUtils.getStringValue;
+import static org.argeo.eclipse.ui.EclipseUiUtils.notEmpty;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.commons.io.IOUtils;
+import org.argeo.connect.ConnectNames;
+import org.argeo.connect.resources.ResourcesNames;
+import org.argeo.connect.resources.ResourcesService;
+import org.argeo.connect.util.ConnectJcrUtils;
+import org.argeo.connect.util.JxlUtils;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.people.ContactValueCatalogs;
+import org.argeo.people.PeopleException;
+import org.argeo.people.PeopleNames;
+import org.argeo.people.PeopleService;
+import org.argeo.people.PeopleTypes;
+import org.argeo.people.util.PeopleJcrUtils;
+import org.argeo.people.util.PersonJcrUtils;
+import org.argeo.suite.SuiteException;
+import org.argeo.suite.workbench.AsUiPlugin;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.rap.fileupload.FileDetails;
+import org.eclipse.rap.fileupload.FileUploadEvent;
+import org.eclipse.rap.fileupload.FileUploadHandler;
+import org.eclipse.rap.fileupload.FileUploadListener;
+import org.eclipse.rap.fileupload.FileUploadReceiver;
+import org.eclipse.rap.rwt.service.ServerPushSession;
+import org.eclipse.rap.rwt.widgets.FileUpload;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+import jxl.Sheet;
+import jxl.Workbook;
+
+/** Open a one page wizard to import an EXCEL 2003 legacy organisation file */
+public class ImportEntities extends AbstractHandler implements PeopleNames {
+
+       public final static String ID = AsUiPlugin.PLUGIN_ID + ".importEntities";
+
+       // public final static String PARAM_NODE_TYPE = "param.nodeType";
+
+       private static final Map<String, String> KNOWN_TEMPLATES;
+       static {
+               Map<String, String> tmpMap = new HashMap<String, String>();
+               tmpMap.put("Organisations", PeopleTypes.PEOPLE_ORG);
+               KNOWN_TEMPLATES = Collections.unmodifiableMap(tmpMap);
+       }
+
+       // TODO make this configurable
+       private final static String IMPORT_ENCODING = "ISO-8859-1";
+
+       /* DEPENDENCY INJECTION */
+       private Repository repository;
+       private ResourcesService resourcesService;
+       private PeopleService peopleService;
+
+       public Object execute(final ExecutionEvent event) throws ExecutionException {
+               // String jcrId = event.getParameter(PARAM_NODE_TYPE);
+
+               Wizard wizard = new ImportMappingFileWizard(HandlerUtil.getActiveShell(event),
+                               "Upload legacy contact via Excel file import");
+               WizardDialog dialog = new WizardDialog(HandlerUtil.getActiveShell(event), wizard);
+               dialog.open();
+               return null;
+       }
+
+       /** One page wizard to import a EXCEL 2003 Mapping files */
+       private class ImportMappingFileWizard extends Wizard {
+
+               // Various UI Objects
+               private UserInputPage userInputPage;
+               private Combo resourceTypeCombo;
+
+               // File upload
+               private FileUpload fileUpload;
+               private Label fileNameLabel;
+               private ServerPushSession pushSession;
+               private File file;
+
+               public ImportMappingFileWizard(Shell parentShell, String title) {
+                       setWindowTitle(title);
+               }
+
+               @Override
+               public void addPages() {
+                       try {
+                               userInputPage = new UserInputPage("User input page");
+                               addPage(userInputPage);
+                       } catch (Exception e) {
+                               throw new SuiteException("Cannot add page to wizard", e);
+                       }
+               }
+
+               /** Performs the real import. */
+               @Override
+               public boolean performFinish() {
+                       // Session session = null;
+                       String templateName = resourceTypeCombo.getItem(resourceTypeCombo.getSelectionIndex());
+                       // String type = KNOWN_TEMPLATES.get(templateName);
+
+                       importDefaultOrgFile(file);
+
+                       return true;
+               }
+
+               @Override
+               public boolean performCancel() {
+                       return true;
+               }
+
+               @Override
+               public boolean canFinish() {
+                       if (resourceTypeCombo.getSelectionIndex() < 0) {
+                               userInputPage.setErrorMessage("Please choose an entity type");
+                               return false;
+                       } else if (file == null) {
+                               userInputPage.setErrorMessage("Please upload a file1");
+                               return false;
+                       } else {
+                               userInputPage.setErrorMessage(null);
+                               return true;
+                       }
+               }
+
+               private class UserInputPage extends WizardPage {
+                       private static final long serialVersionUID = 1L;
+
+                       public UserInputPage(String pageName) {
+                               super(pageName);
+                               setTitle("Upload an Excel 2003 file (.xls)");
+                       }
+
+                       public void createControl(Composite parent) {
+                               parent.setLayout(new GridLayout(1, false));
+                               Composite composite = new Composite(parent, SWT.NONE);
+                               composite.setLayout(new GridLayout(2, false));
+                               composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+                               // Import type
+                               resourceTypeCombo = createLC(composite, "Type");
+                               resourceTypeCombo.addModifyListener(new ModifyListener() {
+                                       private static final long serialVersionUID = 1L;
+
+                                       @Override
+                                       public void modifyText(ModifyEvent event) {
+                                               getWizard().getContainer().updateButtons();
+                                       }
+                               });
+                               resourceTypeCombo.setItems(KNOWN_TEMPLATES.keySet().toArray(new String[0]));
+
+                               // File upload
+                               Label lbl = new Label(composite, SWT.NONE);
+                               lbl.setText("Chosen file");
+                               lbl.setFont(EclipseUiUtils.getBoldFont(composite));
+                               Composite uploadCmp = new Composite(composite, SWT.NONE);
+                               uploadCmp.setLayoutData(EclipseUiUtils.fillWidth());
+                               createFileUploadArea(uploadCmp);
+                               setControl(composite);
+                       }
+               }
+
+               private Control createFileUploadArea(Composite parent) {
+                       GridLayout gl = EclipseUiUtils.noSpaceGridLayout(new GridLayout(2, false));
+                       gl.horizontalSpacing = 5;
+                       parent.setLayout(gl);
+
+                       fileNameLabel = new Label(parent, SWT.NONE | SWT.BEGINNING);
+                       fileNameLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+                       fileUpload = new FileUpload(parent, SWT.NONE);
+                       fileUpload.setText("Browse...");
+                       fileUpload.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+
+                       final String url = startUploadReceiver();
+                       pushSession = new ServerPushSession();
+
+                       fileUpload.addSelectionListener(new SelectionAdapter() {
+                               private static final long serialVersionUID = 1L;
+
+                               @Override
+                               public void widgetSelected(SelectionEvent e) {
+                                       String fileName = fileUpload.getFileName();
+                                       fileNameLabel.setText(fileName == null ? "" : fileName);
+                                       pushSession.start();
+                                       fileUpload.submit(url);
+                               }
+                       });
+                       return parent;
+               }
+
+               private String startUploadReceiver() {
+                       MyFileUploadReceiver receiver = new MyFileUploadReceiver();
+                       FileUploadHandler uploadHandler = new FileUploadHandler(receiver);
+                       uploadHandler.addUploadListener(new FileUploadListener() {
+
+                               public void uploadProgress(FileUploadEvent event) {
+                                       // handle upload progress
+                               }
+
+                               public void uploadFailed(FileUploadEvent event) {
+                                       ImportMappingFileWizard.this.userInputPage
+                                                       .setErrorMessage("upload failed: " + event.getException());
+                               }
+
+                               public void uploadFinished(FileUploadEvent event) {
+                                       fileNameLabel.getDisplay().asyncExec(new Runnable() {
+                                               public void run() {
+                                                       ImportMappingFileWizard.this.getContainer().updateButtons();
+                                                       pushSession.stop();
+                                               }
+                                       });
+                               }
+                       });
+                       return uploadHandler.getUploadUrl();
+               }
+
+               private class MyFileUploadReceiver extends FileUploadReceiver {
+
+                       private static final String TEMP_FILE_PREFIX = "fileupload_";
+
+                       @Override
+                       public void receive(InputStream dataStream, FileDetails details) throws IOException {
+                               File result = File.createTempFile(TEMP_FILE_PREFIX, "");
+                               FileOutputStream outputStream = new FileOutputStream(result);
+                               try {
+                                       copy(dataStream, outputStream);
+                               } finally {
+                                       dataStream.close();
+                                       outputStream.close();
+                               }
+                               if (file != null)
+                                       file.delete();
+                               file = result;
+                       }
+               }
+
+               private void copy(InputStream inputStream, OutputStream outputStream) throws IOException {
+                       byte[] buffer = new byte[8192];
+                       boolean finished = false;
+                       while (!finished) {
+                               int bytesRead = inputStream.read(buffer);
+                               if (bytesRead != -1) {
+                                       outputStream.write(buffer, 0, bytesRead);
+                               } else {
+                                       finished = true;
+                               }
+                       }
+               }
+
+               /** Creates label and Combo. */
+               protected Combo createLC(Composite parent, String label) {
+                       Label lbl = new Label(parent, SWT.RIGHT);
+                       lbl.setText(label);
+                       lbl.setFont(EclipseUiUtils.getBoldFont(parent));
+                       lbl.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+                       Combo combo = new Combo(parent, SWT.READ_ONLY);
+                       combo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+                       return combo;
+               }
+       }
+
+       // Legacy Organisations
+       private Node importDefaultOrgFile(File file) {
+               InputStream in = null;
+               try {
+                       in = new FileInputStream(file);
+                       return importDefaultOrgFile(in);
+               } catch (IOException e) {
+                       throw new SuiteException("Cannot import mapping file", e);
+               } finally {
+                       IOUtils.closeQuietly(in);
+               }
+       }
+
+       private Node createDraftNode(Node parent, String mainMixin) throws RepositoryException {
+               String uuid = UUID.randomUUID().toString();
+               Node tmpNode = parent.addNode(uuid);
+               tmpNode.addMixin(mainMixin);
+               tmpNode.setProperty(ConnectNames.CONNECT_UID, uuid);
+               return tmpNode;
+       }
+
+       private void importOrgEmployees(Node tmpParent, Node targetParent, Node newOrgNode, String coworkersStr)
+                       throws RepositoryException {
+               String[] coworkers = coworkersStr.split("\\n");
+               loop: for (String line : coworkers) {
+                       if (EclipseUiUtils.isEmpty(line))
+                               continue loop;
+                       line = line.trim();
+                       int index = line.indexOf(' ');
+                       String firstName = null;
+                       String lastName = null;
+                       String position = null;
+                       if (index == -1)
+                               firstName = line;
+                       else {
+                               firstName = line.substring(0, index);
+                               line = line.substring(index);
+
+                               index = line.indexOf('(');
+                               if (index == -1)
+                                       lastName = line;
+                               else {
+                                       lastName = line.substring(0, index).trim();
+                                       position = line.substring(index + 1, line.length() - 1);
+                               }
+                       }
+                       Node tmpPerson = createDraftNode(tmpParent, PeopleTypes.PEOPLE_PERSON);
+                       tmpPerson.setProperty(PEOPLE_FIRST_NAME, firstName);
+                       if (EclipseUiUtils.notEmpty(lastName))
+                               tmpPerson.setProperty(PEOPLE_LAST_NAME, lastName);
+                       Node newPersonNode = peopleService.createEntity(targetParent, PeopleTypes.PEOPLE_PERSON, tmpPerson);
+                       if (EclipseUiUtils.notEmpty(position))
+                               PersonJcrUtils.addJob(newPersonNode, newOrgNode, position, true);
+                       // Save the newly created entity without creating a base version
+                       newOrgNode = peopleService.saveEntity(newOrgNode, false);
+
+               }
+       }
+
+       private void importUrls(Node contactable, String urlStr) throws RepositoryException {
+               String[] urls = urlStr.split("\\n");
+               boolean hasPrimary = false;
+               boolean hasPrimaryFacebook = false;
+
+               loop: for (String line : urls) {
+                       if (EclipseUiUtils.isEmpty(line))
+                               continue loop;
+                       line = line.trim();
+
+                       if (line.startsWith("https://www.facebook.com")) {
+                               PeopleJcrUtils.createSocialMedia(peopleService, resourcesService, contactable, line,
+                                               !hasPrimaryFacebook, null, ContactValueCatalogs.CONTACT_CAT_FACEBOOK, null);
+                               hasPrimaryFacebook = true;
+                       } else {
+                               PeopleJcrUtils.createWebsite(peopleService, resourcesService, contactable, line, !hasPrimary, null,
+                                               null);
+                               hasPrimary = true;
+                       }
+               }
+       }
+
+       private void importMails(Node contactable, String mailStr) throws RepositoryException {
+               String[] urls = mailStr.split("\\n");
+               boolean hasPrimary = false;
+               loop: for (String line : urls) {
+                       if (EclipseUiUtils.isEmpty(line))
+                               continue loop;
+                       line = line.trim();
+                       PeopleJcrUtils.createEmail(peopleService, resourcesService, contactable, line, !hasPrimary, null, null,
+                                       null);
+                       hasPrimary = true;
+               }
+       }
+
+       // TODO make this configurable
+       int displayNameIndex = 0;
+       int legalNameIndex = 1;
+       int legalFormIndex = 2;
+       int urlsIndex = 3;
+       int streetIndex = 4;
+       int postalCodeIndex = 5;
+       int lIndex = 6;
+       int stIndex = 7;
+       int cIndex = 8;
+       int mobileIndex = 9;
+       int telephoneNumberIndex = 10;
+       int mailIndex = 11;
+       int contactsIndex = 12;
+       int descriptionIndex = 13;
+       int tagsIndex = 14;
+
+       private Node importDefaultOrgFile(InputStream in) throws IOException {
+               Session session = null;
+               int i = 0;
+               try {
+                       Workbook wb = JxlUtils.toWorkbook(in, IMPORT_ENCODING);
+                       session = repository.login();
+                       String basePath = "/" + peopleService.getBaseRelPath(PeopleTypes.PEOPLE_ORG);
+                       Node targetParent = session.getNode(basePath);
+                       Sheet sheet = wb.getSheet(0);
+
+                       Node tmpParent = peopleService.getDraftParent(session);
+
+                       int rowNb = sheet.getRows();
+                       for (i = 1; i < rowNb - 1; i++) {
+
+                               Node tmpOrg = createDraftNode(tmpParent, PeopleTypes.PEOPLE_ORG);
+
+                               String dName = JxlUtils.getStringValue(sheet, displayNameIndex, i);
+                               if (notEmpty(dName))
+                                       tmpOrg.setProperty(PeopleNames.PEOPLE_DISPLAY_NAME, dName);
+                               String lName = getStringValue(sheet, legalNameIndex, i);
+                               if (notEmpty(lName))
+                                       tmpOrg.setProperty(PeopleNames.PEOPLE_LEGAL_NAME, lName);
+                               String lForm = getStringValue(sheet, legalFormIndex, i);
+                               if (notEmpty(lForm))
+                                       tmpOrg.setProperty(PeopleNames.PEOPLE_LEGAL_FORM, lForm);
+                               String urlStr = getStringValue(sheet, urlsIndex, i);
+                               if (notEmpty(urlStr))
+                                       importUrls(tmpOrg, urlStr);
+                               String mailStr = getStringValue(sheet, mailIndex, i);
+                               if (notEmpty(mailStr))
+                                       importMails(tmpOrg, mailStr);
+                               String streetStr = getStringValue(sheet, streetIndex, i);
+                               String pcStr = getStringValue(sheet, postalCodeIndex, i);
+                               String lStr = getStringValue(sheet, lIndex, i);
+                               String stStr = getStringValue(sheet, stIndex, i);
+                               String cStr = getStringValue(sheet, cIndex, i);
+                               if (notEmpty(streetStr) || notEmpty(pcStr) || notEmpty(lStr) || notEmpty(stStr) || notEmpty(cStr))
+                                       PeopleJcrUtils.createAddress(peopleService, resourcesService, tmpOrg, streetStr, null, pcStr, lStr,
+                                                       stStr, cStr, true, null, ContactValueCatalogs.CONTACT_CAT_MAIN, null);
+                               String mobileStr = getStringValue(sheet, mobileIndex, i);
+                               if (notEmpty(mobileStr))
+                                       PeopleJcrUtils.createPhone(peopleService, resourcesService, tmpOrg, mobileStr, true, null,
+                                                       ContactValueCatalogs.CONTACT_CAT_MOBILE, null);
+                               String phoneStr = getStringValue(sheet, telephoneNumberIndex, i);
+                               if (notEmpty(phoneStr))
+                                       PeopleJcrUtils.createPhone(peopleService, resourcesService, tmpOrg, phoneStr, true, null,
+                                                       ContactValueCatalogs.CONTACT_CAT_DIRECT, null);
+                               String descStr = getStringValue(sheet, descriptionIndex, i);
+                               if (notEmpty(descStr))
+                                       tmpOrg.setProperty(Property.JCR_DESCRIPTION, descStr);
+                               String tagsStr = getStringValue(sheet, tagsIndex, i);
+                               if (notEmpty(tagsStr))
+                                       tmpOrg.setProperty(ResourcesNames.CONNECT_TAGS, ConnectJcrUtils.parseAndClean(tagsStr, ",", true));
+
+                               Node newOrgNode = peopleService.createEntity(targetParent, PeopleTypes.PEOPLE_ORG, tmpOrg);
+                               // Save the newly created entity without creating a base version
+                               newOrgNode = peopleService.saveEntity(newOrgNode, false);
+
+                               String contactsStr = getStringValue(sheet, contactsIndex, i);
+                               if (notEmpty(contactsStr))
+                                       importOrgEmployees(tmpParent, targetParent, newOrgNode, contactsStr);
+
+                       }
+               } catch (PeopleException | RepositoryException e) {
+                       throw new SuiteException("Cannot import mapping file, error at line: " + (i + 1), e);
+               } finally {
+                       JcrUtils.logoutQuietly(session);
+               }
+
+               return null;
+       }
+
+       /* DEPENDENCY INJECTION */
+       public void setRepository(Repository repository) {
+               this.repository = repository;
+       }
+
+       public void setResourcesService(ResourcesService resourcesService) {
+               this.resourcesService = resourcesService;
+       }
+
+       public void setPeopleService(PeopleService peopleService) {
+               this.peopleService = peopleService;
+       }
+}
diff --git a/org.argeo.suite.workbench.rap/theme/argeo-classic/icons/more.gif b/org.argeo.suite.workbench.rap/theme/argeo-classic/icons/more.gif
new file mode 100644 (file)
index 0000000..57ad089
Binary files /dev/null and b/org.argeo.suite.workbench.rap/theme/argeo-classic/icons/more.gif differ
diff --git a/org.argeo.suite.workbench.rap/theme/argeo-classic/icons/upload.gif b/org.argeo.suite.workbench.rap/theme/argeo-classic/icons/upload.gif
new file mode 100644 (file)
index 0000000..d38085a
Binary files /dev/null and b/org.argeo.suite.workbench.rap/theme/argeo-classic/icons/upload.gif differ