├── templates ├── widget │ └── src │ │ └── main │ │ ├── resources │ │ ├── widgetname.properties │ │ ├── edit.ftl │ │ ├── view.ftl │ │ └── application.info │ │ └── webapp │ │ ├── resources │ │ ├── css │ │ │ └── widgetname.css │ │ ├── images │ │ │ └── icon.png │ │ └── js │ │ │ └── widgetname.js │ │ └── WEB-INF │ │ ├── jboss-web.xml │ │ └── web.xml ├── formEvents │ ├── setEnable.txt │ ├── afterSaveNew.txt │ ├── enableFields.txt │ ├── inputFields.txt │ ├── validateForm.txt │ ├── afterProcessing.txt │ ├── beforeProcessing.txt │ └── displayFields.txt ├── globalEvents │ ├── afterDeleteCard.txt │ ├── afterSaveCard.txt │ ├── beforeSocialUnlike.txt │ ├── afterCreateUser.txt │ ├── afterLogin.txt │ ├── afterSocialPost.txt │ ├── afterUpdateUser.txt │ ├── onLogout.txt │ ├── beforeLogin.txt │ ├── beforeSocialPostEdit.txt │ ├── afterActivateUser.txt │ ├── afterDocumentPublisher.txt │ ├── afterDeactivateUser.txt │ ├── afterSendNotification.txt │ ├── afterSocialLike.txt │ ├── beforeActivateUser.txt │ ├── afterSocialComment.txt │ ├── afterSocialPostRemove.txt │ ├── afterSocialUnlike.txt │ ├── displayCentralTasks.txt │ ├── addDocumentConvertionExt.txt │ ├── afterSocialCommentEdit.txt │ ├── beforeSocialCommentEdit.txt │ ├── onApplyDocumentPrintProperties.txt │ ├── afterSocialPostEdit.txt │ ├── onApplyDocumentPublishProperties.txt │ ├── afterSocialShare.txt │ ├── beforeSocialPost.txt │ ├── beforeSendNotification.txt │ ├── validateCustomMetadata.txt │ ├── beforeSocialComment.txt │ ├── onApplyDocumentProtocolProperties.txt │ ├── afterSocialFollow.txt │ ├── beforeSocialFollow.txt │ ├── afterSocialDenounce.txt │ ├── afterSocialUnfollow.txt │ ├── beforeSocialDenounce.txt │ ├── beforeSocialLike.txt │ ├── beforeSocialUnfollow.txt │ ├── afterCommunityLeave.txt │ ├── afterSocialCommentRemove.txt │ ├── beforeSocialPostRemove.txt │ ├── displayCustomMetadata.txt │ ├── afterSocialPictureChange.txt │ ├── beforeSocialCommentRemove.txt │ ├── afterCommunityParticipation.txt │ ├── beforeSocialPictureChange.txt │ ├── beforeUnwatchContent.txt │ ├── onLoginError.txt │ ├── afterWatchContent.txt │ ├── afterUnwatchContent.txt │ ├── beforeCommunityLeave.txt │ ├── beforeCommunityParticipation.txt │ ├── beforeSocialShare.txt │ ├── afterDocumentRemovePermanently.txt │ ├── beforeDocumentRemovePermanently.txt │ ├── onNotify.txt │ ├── afterReleaseProcessVersion.txt │ ├── beforeCreateUser.txt │ ├── afterDocumentRestore.txt │ ├── beforeDocumentRestore.txt │ ├── beforeDownloadContent.txt │ ├── beforeUpdateUser.txt │ ├── onDisplayTasksSummary.txt │ ├── afterDocumentRemove.txt │ ├── beforeDocumentRemove.txt │ ├── beforeDocumentViewer.txt │ ├── beforeDeactivateUser.txt │ ├── beforeDocumentPublisher.txt │ ├── beforeWatchContent.txt │ ├── onDisplayTasks.txt │ └── validateUpload.txt ├── workflowEvents │ ├── afterStateLeave.txt │ ├── afterProcessCreate.txt │ ├── afterProcessFinish.txt │ ├── beforeStateLeave.txt │ ├── subProcessCreated.txt │ ├── afterReleaseVersion.txt │ ├── afterStateEntry.txt │ ├── afterReleaseProcessVersion.txt │ ├── afterTaskCreate.txt │ ├── beforeStateEntry.txt │ ├── beforeTaskCreate.txt │ ├── checkComplementsPermission.txt │ ├── afterCancelProcess.txt │ ├── beforeCancelProcess.txt │ ├── validateAvailableStates.txt │ ├── beforeSendData.txt │ ├── beforeTaskSave.txt │ ├── beforeTaskComplete.txt │ ├── afterTaskComplete.txt │ ├── afterTaskSave.txt │ └── calculateAgreement.txt ├── createMechanism.txt ├── createDataset.txt └── form.txt ├── .gitignore ├── images ├── icon.png ├── menu_f1.jpg └── menu_contexto.jpg ├── resources ├── images │ ├── icon-brand.png │ ├── dark │ │ ├── add.svg │ │ ├── preview.svg │ │ ├── edit.svg │ │ ├── trash.svg │ │ ├── refresh.svg │ │ ├── database.svg │ │ └── server-environment.svg │ └── light │ │ ├── add.svg │ │ ├── edit.svg │ │ ├── preview.svg │ │ ├── trash.svg │ │ ├── refresh.svg │ │ ├── database.svg │ │ └── server-environment.svg ├── views │ ├── server │ │ ├── server.js │ │ └── server.html │ └── dataset │ │ ├── dataset.css │ │ ├── dataset.html │ │ └── dataset.js └── css │ └── theme.css ├── src ├── models │ ├── AttachmentDTO.ts │ ├── AttachmentArrayDTO.ts │ ├── CustomizationEventsDTO.ts │ ├── WidgetFluiggersDTO.ts │ ├── ServerConfig.ts │ ├── GlobalEventDTO.ts │ ├── CustomizationEventsArrayDTO.ts │ ├── DatasetDTO.ts │ ├── FormGeneralInfoDto.ts │ ├── ServerDTO.ts │ ├── DatasetStructureDTO.ts │ ├── AttributionMechanismDTO.ts │ ├── FormDTO.ts │ ├── Server.ts │ └── DocumentDTO.ts ├── services │ ├── GlobalStorageService.ts │ ├── UserService.ts │ ├── TemplateService.ts │ ├── CryptoService.ts │ ├── LoginService.ts │ ├── UtilsService.ts │ ├── WorkflowService.ts │ ├── ServerService.ts │ ├── GlobalEventService.ts │ └── AttributionMechanismService.ts ├── extensions │ ├── TemplateExtension.ts │ ├── WidgetExtension.ts │ ├── ServerExtension.ts │ ├── LibraryExtension.ts │ ├── GlobalEventExtension.ts │ ├── DatasetExtension.ts │ ├── FormExtension.ts │ └── WorkflowExtension.ts ├── extension.ts ├── views │ ├── ServerView.ts │ └── DatasetView.ts └── providers │ └── ServerItemProvider.ts ├── .vscode ├── tasks.json ├── settings.json └── launch.json ├── .vscodeignore ├── .editorconfig ├── .github └── ISSUE_TEMPLATE │ ├── feature.md │ └── bug.md ├── .eslintrc.json ├── tsconfig.json ├── LICENSE ├── webpack.config.js └── gulpfile.js /templates/widget/src/main/resources/widgetname.properties: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | dist 3 | node_modules 4 | .vscode-test/ 5 | *.vsix 6 | .idea/ 7 | -------------------------------------------------------------------------------- /images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluiggers/fluig-vscode-extension/HEAD/images/icon.png -------------------------------------------------------------------------------- /templates/formEvents/setEnable.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | */ 5 | function setEnable() { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /templates/globalEvents/afterDeleteCard.txt: -------------------------------------------------------------------------------- 1 | function afterDeleteCard(companyId, cardId) { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /templates/widget/src/main/webapp/resources/css/widgetname.css: -------------------------------------------------------------------------------- 1 | /* Coloque aqui seu codigo CSS */ 2 | -------------------------------------------------------------------------------- /images/menu_f1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluiggers/fluig-vscode-extension/HEAD/images/menu_f1.jpg -------------------------------------------------------------------------------- /images/menu_contexto.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluiggers/fluig-vscode-extension/HEAD/images/menu_contexto.jpg -------------------------------------------------------------------------------- /resources/images/icon-brand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluiggers/fluig-vscode-extension/HEAD/resources/images/icon-brand.png -------------------------------------------------------------------------------- /templates/globalEvents/afterSaveCard.txt: -------------------------------------------------------------------------------- 1 | function afterSaveCard(companyId, formId, cardId, cardVersion, cardData) { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /templates/formEvents/afterSaveNew.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {FormController} form 5 | */ 6 | function afterSaveNew(form) { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /templates/formEvents/enableFields.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {FormController} form 5 | */ 6 | function enableFields(form) { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /templates/formEvents/inputFields.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {FormController} form 5 | */ 6 | function inputFields(form) { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /templates/formEvents/validateForm.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {FormController} form 5 | */ 6 | function validateForm(form) { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /templates/globalEvents/beforeSocialUnlike.txt: -------------------------------------------------------------------------------- 1 | function beforeSocialUnlike(companyId, unlike) { 2 | throw "You can not unlike a post."; 3 | } 4 | -------------------------------------------------------------------------------- /src/models/AttachmentDTO.ts: -------------------------------------------------------------------------------- 1 | export interface AttachmentDTO { 2 | fileName: string; 3 | filecontent: string; 4 | principal: boolean; 5 | } 6 | -------------------------------------------------------------------------------- /templates/globalEvents/afterCreateUser.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {UserEventVO} user 5 | */ 6 | function afterCreateUser(user) { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /templates/formEvents/afterProcessing.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {FormController} form 5 | */ 6 | function afterProcessing(form) { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /templates/formEvents/beforeProcessing.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {FormController} form 5 | */ 6 | function beforeProcessing(form) { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /templates/globalEvents/afterLogin.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {string} login Login do usuário 5 | */ 6 | function afterLogin(login) { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /templates/globalEvents/afterSocialPost.txt: -------------------------------------------------------------------------------- 1 | function afterSocialPost(companyId, post) { 2 | log.info(post.getUser() + " has published a content."); 3 | } 4 | -------------------------------------------------------------------------------- /templates/globalEvents/afterUpdateUser.txt: -------------------------------------------------------------------------------- 1 | function afterUpdateUser(user) { 2 | log.info("O usuário " + user.getFullName() + " foi alterado."); 3 | } 4 | -------------------------------------------------------------------------------- /templates/globalEvents/onLogout.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {string} login Login do usuário 5 | */ 6 | function onLogout(login) { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /templates/globalEvents/beforeLogin.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {string} login Login do usuário 5 | */ 6 | function beforeLogin(login) { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /templates/workflowEvents/afterStateLeave.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {number} sequenceId 5 | */ 6 | function afterStateLeave(sequenceId) { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /templates/globalEvents/beforeSocialPostEdit.txt: -------------------------------------------------------------------------------- 1 | function beforeSocialPostEdit(companyId, vo) { 2 | vo.setText(vo.getText() + " \n --- Conteúdo editado ---"); 3 | } 4 | -------------------------------------------------------------------------------- /templates/workflowEvents/afterProcessCreate.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {number} processId 5 | */ 6 | function afterProcessCreate(processId) { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /templates/workflowEvents/afterProcessFinish.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {number} processId 5 | */ 6 | function afterProcessFinish(processId) { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /templates/workflowEvents/beforeStateLeave.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {number} sequenceId 5 | */ 6 | function beforeStateLeave(sequenceId) { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /templates/workflowEvents/subProcessCreated.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {number} processId 5 | */ 6 | function subProcessCreated(processId) { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/models/AttachmentArrayDTO.ts: -------------------------------------------------------------------------------- 1 | import { AttachmentDTO } from "./AttachmentDTO"; 2 | 3 | export interface AttachmentArrayDTO { 4 | item: AttachmentDTO[]; 5 | } 6 | -------------------------------------------------------------------------------- /templates/globalEvents/afterActivateUser.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {string} login Login do usuário 5 | */ 6 | function afterActivateUser(login) { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /templates/globalEvents/afterDocumentPublisher.txt: -------------------------------------------------------------------------------- 1 | function afterDocumentPublisher() { 2 | // Verificar documentação de exemplo do Evento BeforeDocumentPublisher 3 | } 4 | -------------------------------------------------------------------------------- /templates/workflowEvents/afterReleaseVersion.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {string} processXML 5 | */ 6 | function afterReleaseVersion(processXML) { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /templates/workflowEvents/afterStateEntry.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {number} sequenceId 5 | */ 6 | function afterStateEntry(sequenceId) { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /templates/globalEvents/afterDeactivateUser.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {string} login Login do usuário 5 | */ 6 | function afterDeactivateUser(login) { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /templates/globalEvents/afterSendNotification.txt: -------------------------------------------------------------------------------- 1 | function afterSendNotification(notification) { 2 | log.info("notification as send for " + notification.aliasReceiver); 3 | } 4 | -------------------------------------------------------------------------------- /templates/globalEvents/afterSocialLike.txt: -------------------------------------------------------------------------------- 1 | function afterSocialLike(companyId, like) { 2 | log.info(like.getUser() + " has liked the " + like.getSociable().getUrl()); 3 | } 4 | -------------------------------------------------------------------------------- /templates/globalEvents/beforeActivateUser.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {string} login Login do usuário 5 | */ 6 | function beforeActivateUser(login) { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/models/CustomizationEventsDTO.ts: -------------------------------------------------------------------------------- 1 | export interface CustomizationEventsDTO { 2 | eventDescription: string; 3 | eventId: string; 4 | eventVersAnt?: boolean; 5 | } 6 | -------------------------------------------------------------------------------- /src/models/WidgetFluiggersDTO.ts: -------------------------------------------------------------------------------- 1 | export interface WidgetFluiggersDTO { 2 | code: string; 3 | filename: string; 4 | description: string; 5 | title: string; 6 | } 7 | -------------------------------------------------------------------------------- /src/models/ServerConfig.ts: -------------------------------------------------------------------------------- 1 | import { ServerDTO } from "./ServerDTO"; 2 | 3 | export interface ServerConfig { 4 | version: String, 5 | configurations: ServerDTO[] 6 | } 7 | -------------------------------------------------------------------------------- /templates/globalEvents/afterSocialComment.txt: -------------------------------------------------------------------------------- 1 | function afterSocialComment(companyId, comment) { 2 | log.info(comment.getUser() + " has done the comment " + comment.getText()); 3 | } 4 | -------------------------------------------------------------------------------- /templates/globalEvents/afterSocialPostRemove.txt: -------------------------------------------------------------------------------- 1 | function afterSocialPostRemove(companyId, post) { 2 | log.info(post.getUser() + " has removed the post " + post.getPostId()); 3 | } 4 | -------------------------------------------------------------------------------- /templates/widget/src/main/webapp/resources/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluiggers/fluig-vscode-extension/HEAD/templates/widget/src/main/webapp/resources/images/icon.png -------------------------------------------------------------------------------- /templates/workflowEvents/afterReleaseProcessVersion.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {string} processXML 5 | */ 6 | function afterReleaseProcessVersion(processXML) { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /templates/workflowEvents/afterTaskCreate.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {string} colleagueId Matrícula do Usuário 5 | */ 6 | function afterTaskCreate(colleagueId) { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /templates/workflowEvents/beforeStateEntry.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {number} sequenceId Sequência da atividade 5 | */ 6 | function beforeStateEntry(sequenceId) { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /templates/workflowEvents/beforeTaskCreate.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {string} colleagueId Matrícula do Usuário 5 | */ 6 | function beforeTaskCreate(colleagueId) { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /templates/globalEvents/afterSocialUnlike.txt: -------------------------------------------------------------------------------- 1 | function afterSocialUnlike(companyId, unlike) { 2 | log.info(unlike.getUser() + " has unliked the " + unlike.getSociable().getUrl()); 3 | } 4 | -------------------------------------------------------------------------------- /templates/globalEvents/displayCentralTasks.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {java.util.LinkedHashMap} links 5 | */ 6 | function displayCentralTasks(links) { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /templates/widget/src/main/resources/edit.ftl: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /templates/widget/src/main/resources/view.ftl: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /templates/globalEvents/addDocumentConvertionExt.txt: -------------------------------------------------------------------------------- 1 | function addDocumentConvertionExt(ext) { 2 | // Exemplo de implementação 3 | ext.add("xls"); 4 | ext.add("doc"); 5 | ext.add("txt"); 6 | } 7 | -------------------------------------------------------------------------------- /templates/globalEvents/afterSocialCommentEdit.txt: -------------------------------------------------------------------------------- 1 | function afterSocialCommentEdit(companyId, comment) { 2 | log.info(comment.getUser() + " editou o coment" + comment.getCommentId()); 3 | } 4 | -------------------------------------------------------------------------------- /templates/globalEvents/beforeSocialCommentEdit.txt: -------------------------------------------------------------------------------- 1 | function beforeSocialCommentEdit(companyId, comment) { 2 | comment.setText(comment.getText() + " \n --- Comentário editado ---"); 3 | } 4 | -------------------------------------------------------------------------------- /src/models/GlobalEventDTO.ts: -------------------------------------------------------------------------------- 1 | export interface GlobalEventDTO { 2 | globalEventPK: { 3 | companyId: number; 4 | eventId: string; 5 | }; 6 | eventDescription: string; 7 | } 8 | -------------------------------------------------------------------------------- /templates/formEvents/displayFields.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {FormController} form 5 | * @param {customHTML} customHTML 6 | */ 7 | function displayFields(form, customHTML) { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /templates/globalEvents/onApplyDocumentPrintProperties.txt: -------------------------------------------------------------------------------- 1 | function onApplyDocumentPrintProperties(fields) { 2 | // Exemplo implementação 3 | fields.put("Document.PrintedDocument.Copies", "2"); 4 | } 5 | -------------------------------------------------------------------------------- /templates/workflowEvents/checkComplementsPermission.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @returns {boolean} Se retornar false impede adição de complemento 5 | */ 6 | function checkComplementsPermission() { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/models/CustomizationEventsArrayDTO.ts: -------------------------------------------------------------------------------- 1 | import { CustomizationEventsDTO } from "./CustomizationEventsDTO"; 2 | 3 | export interface CustomizationEventsArrayDTO { 4 | item: CustomizationEventsDTO[]; 5 | } 6 | -------------------------------------------------------------------------------- /templates/globalEvents/afterSocialPostEdit.txt: -------------------------------------------------------------------------------- 1 | function afterSocialPostEdit(companyId, post) { 2 | log.info(post.getUser() + " editou o conteúdo post: " + post.getPostId()); 3 | log.info(post.getText()); 4 | } 5 | -------------------------------------------------------------------------------- /templates/globalEvents/onApplyDocumentPublishProperties.txt: -------------------------------------------------------------------------------- 1 | function onApplyDocumentPublishProperties(fields) { 2 | // Exemplo implementação 3 | fields.put("Document.Author", "Autor do Documento"); 4 | } 5 | -------------------------------------------------------------------------------- /templates/globalEvents/afterSocialShare.txt: -------------------------------------------------------------------------------- 1 | function afterSocialShare(companyId, share) { 2 | log.info(share.getUser() + " has shared the sociable " + share.getSociable().getId() + " with text " + share.getText()); 3 | } 4 | -------------------------------------------------------------------------------- /templates/globalEvents/beforeSocialPost.txt: -------------------------------------------------------------------------------- 1 | function beforeSocialPost(companyId, vo) { 2 | if (vo.getText().indexOf(" fluid ") > -1) { 3 | vo.setText(vo.getText().replace(" fluid ", " fluig ")); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /templates/globalEvents/beforeSendNotification.txt: -------------------------------------------------------------------------------- 1 | function beforeSendNotification(notification) { 2 | if ("DOCUMENT_APPROVAL_PENDING" == notification.eventType) { 3 | notification.priority = "HIGH"; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/models/DatasetDTO.ts: -------------------------------------------------------------------------------- 1 | export interface DatasetDTO { 2 | companyId: number; 3 | datasetId: string; 4 | mobileOffline: boolean; 5 | serverOffline: boolean; 6 | type: string; 7 | version: number; 8 | } 9 | -------------------------------------------------------------------------------- /templates/globalEvents/validateCustomMetadata.txt: -------------------------------------------------------------------------------- 1 | function validateCustomMetadata(fields) { 2 | //Exemplo implementa 3 | 4 | if (fields.getValue("campo1") == 1) { 5 | throw "TRATAMENTO DA EXCEÇÃO"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /templates/globalEvents/beforeSocialComment.txt: -------------------------------------------------------------------------------- 1 | function beforeSocialComment(companyId, comment) { 2 | if (comment.getSociable().getNumberLikes() < 1) { 3 | throw "You can not comment a post that was not liked."; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /templates/globalEvents/onApplyDocumentProtocolProperties.txt: -------------------------------------------------------------------------------- 1 | function onApplyDocumentProtocolProperties(fields) { 2 | // Exemplo implementação 3 | fields.put("Document.PrintedDocument.Description", "Descrição do documento"); 4 | } 5 | -------------------------------------------------------------------------------- /templates/widget/src/main/webapp/WEB-INF/jboss-web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | /widgetname 4 | false 5 | 6 | -------------------------------------------------------------------------------- /resources/images/dark/add.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /resources/images/light/add.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /templates/globalEvents/afterSocialFollow.txt: -------------------------------------------------------------------------------- 1 | function afterSocialFollow(companyId, follow) { 2 | log.info("afterSocialFollow Social Alias: " + follow.getSocial().getAlias() + " Followed Alias: " + follow.getFollowed().getAlias()); 3 | } 4 | -------------------------------------------------------------------------------- /templates/globalEvents/beforeSocialFollow.txt: -------------------------------------------------------------------------------- 1 | function beforeSocialFollow(companyId, follow) { 2 | log.info("beforeSocialFollow Social Alias: " + follow.getSocial().getAlias() + " Followed Alias: " + follow.getFollowed().getAlias()); 3 | } 4 | -------------------------------------------------------------------------------- /templates/workflowEvents/afterCancelProcess.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {string} colleagueId Matrícula do Usuário 5 | * @param {number} processId 6 | */ 7 | function afterCancelProcess(colleagueId, processId) { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /templates/workflowEvents/beforeCancelProcess.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {string} colleagueId Matrícula do Usuário 5 | * @param {number} processId 6 | */ 7 | function beforeCancelProcess(colleagueId, processId) { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /templates/globalEvents/afterSocialDenounce.txt: -------------------------------------------------------------------------------- 1 | function afterSocialDenounce(companyId, denounce) { 2 | log.info(denounce.getUser() + " has denounced the sociable " + denounce.getSociable().getId() + " with comment " + denounce.getText()); 3 | } 4 | -------------------------------------------------------------------------------- /templates/globalEvents/afterSocialUnfollow.txt: -------------------------------------------------------------------------------- 1 | function afterSocialUnfollow(companyId, follow) { 2 | log.info("afterSocialUnfollow Social Alias: " + follow.getSocial().getAlias() + " Followed Alias: " + follow.getFollowed().getAlias()); 3 | } 4 | -------------------------------------------------------------------------------- /templates/globalEvents/beforeSocialDenounce.txt: -------------------------------------------------------------------------------- 1 | function beforeSocialDenounce(companyId, denounce) { 2 | if (denounce.getSociable().getText().toLowerCase().indexOf("#cipa") > -1) { 3 | throw "You cannot denounce posts about CIPA."; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /templates/globalEvents/beforeSocialLike.txt: -------------------------------------------------------------------------------- 1 | function beforeSocialLike(companyId, like) { 2 | if (like.getSociable().getText().toLowerCase().indexOf("#greve") > -1) { 3 | throw "You can not like a post that has this type of comment."; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /templates/globalEvents/beforeSocialUnfollow.txt: -------------------------------------------------------------------------------- 1 | function beforeSocialUnfollow(companyId, follow) { 2 | log.info("beforeSocialUnfollow Social Alias: " + follow.getSocial().getAlias() + " Followed Alias: " + follow.getFollowed().getAlias()); 3 | } 4 | -------------------------------------------------------------------------------- /templates/globalEvents/afterCommunityLeave.txt: -------------------------------------------------------------------------------- 1 | function afterCommunityLeave(companyId, relation) { 2 | log.info("afterCommunityLeave Social Alias: " + relation.getSocial().getAlias() + " Community Alias: " + relation.getCommunity().getAlias()); 3 | } 4 | -------------------------------------------------------------------------------- /templates/globalEvents/afterSocialCommentRemove.txt: -------------------------------------------------------------------------------- 1 | function afterSocialCommentRemove(companyId, comment) { 2 | log.info(comment.getUser() + " has removed the comment " + comment.getText() + " of the sociable " + comment.getSociable().getId()); 3 | } 4 | -------------------------------------------------------------------------------- /templates/globalEvents/beforeSocialPostRemove.txt: -------------------------------------------------------------------------------- 1 | function beforeSocialPostRemove(companyId, post) { 2 | if (post.getText().toLowerCase().indexOf("#important") > -1) { 3 | throw "You cannot remove a post marked as important."; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /templates/workflowEvents/validateAvailableStates.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {number} iCurrentState 5 | * @param {java.util.List} stateList 6 | */ 7 | function validateAvailableStates(iCurrentState, stateList) { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /templates/globalEvents/displayCustomMetadata.txt: -------------------------------------------------------------------------------- 1 | function displayCustomMetadata(fields) { 2 | // Exemplo de implementa 3 | log.info("Valor do Campo 1: " + fields.getValue("campo1")); 4 | fields.setValue("campo1", "Valor para o Campo 1"); 5 | } 6 | -------------------------------------------------------------------------------- /templates/globalEvents/afterSocialPictureChange.txt: -------------------------------------------------------------------------------- 1 | function afterSocialPictureChange(companyId, vo) { 2 | log.info(vo.getAlias()); 3 | log.info(vo.getPath()); 4 | log.info(vo.getPictureName()); 5 | log.info(vo.getWidth()); 6 | log.info(vo.getHeight()); 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": [ 3 | { 4 | "type": "npm", 5 | "script": "compile", 6 | "group": { 7 | "kind": "build", 8 | "isDefault": true 9 | }, 10 | "problemMatcher": [], 11 | "label": "npm: compile" 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /src/models/FormGeneralInfoDto.ts: -------------------------------------------------------------------------------- 1 | export interface FormGeneralInfoDto { 2 | /** 3 | * 0 - não muda versão 4 | * 1 - adiciona 1 dígito ao final da versão 5 | * 2 - adiciona 1 dígito ao início da versão 6 | */ 7 | versionOption: string; 8 | } 9 | -------------------------------------------------------------------------------- /templates/globalEvents/beforeSocialCommentRemove.txt: -------------------------------------------------------------------------------- 1 | function beforeSocialCommentRemove(companyId, comment) { 2 | if (comment.getSociable().getText().toLowerCase().indexOf("#bolaototvs") > -1) { 3 | throw "You cannot change your guess."; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /templates/globalEvents/afterCommunityParticipation.txt: -------------------------------------------------------------------------------- 1 | function afterCommunityParticipation(companyId, relation) { 2 | log.info("afterCommunityParticipation Social Alias: " + relation.getSocial().getAlias() + " Community Alias: " + relation.getCommunity().getAlias()); 3 | } 4 | -------------------------------------------------------------------------------- /templates/globalEvents/beforeSocialPictureChange.txt: -------------------------------------------------------------------------------- 1 | function beforeSocialPictureChange(companyId, vo) { 2 | log.info(vo.getAlias()); 3 | log.info(vo.getPath()); 4 | log.info(vo.getPictureName()); 5 | log.info(vo.getWidth()); 6 | log.info(vo.getHeight()); 7 | } 8 | -------------------------------------------------------------------------------- /templates/globalEvents/beforeUnwatchContent.txt: -------------------------------------------------------------------------------- 1 | function beforeUnwatchContent(companyId, watchDTO) { 2 | if (watchDTO.getSocialWatchType() == "COMMUNITY") { 3 | throw "Você não pode deixar de ser notificado sobre a comunidade " + watchDTO.getDescription(); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | out/** 4 | src/** 5 | .gitignore 6 | .yarnrc 7 | **/tsconfig.json 8 | **/.eslintrc.json 9 | **/*.map 10 | **/*.ts 11 | node_modules/** 12 | resources/** 13 | gulpfile.js 14 | webpack.config.js 15 | templates/** 16 | .github/** 17 | -------------------------------------------------------------------------------- /templates/workflowEvents/beforeSendData.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @param {string[]} customFields Array com 30 posições já instanciadas 4 | * @param {number[]} customFacts Array do tipo double com mais de 10 posições 5 | */ 6 | function beforeSendData(customFields, customFacts) { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /templates/globalEvents/onLoginError.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {string} login Login do usuário 5 | * @param {number} errorCause Causa do erro. Pode ser 0 para Login e Senha Inválidos, 1 para Usuário Inativo 6 | */ 7 | function onLoginError(login, errorCause) { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 4 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | -------------------------------------------------------------------------------- /templates/globalEvents/afterWatchContent.txt: -------------------------------------------------------------------------------- 1 | function afterWatchContent(companyId, watchDTO) { 2 | if (watchDTO.getSocialWatchType() == "POST") { 3 | log.info( "O usuário " + watchDTO.getUserAlias() + " vai ser notificado sobre o post " + watchDTO.getText() + " do autor " + watchDTO.getPostAuthor()); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /templates/globalEvents/afterUnwatchContent.txt: -------------------------------------------------------------------------------- 1 | function afterUnwatchContent(companyId, watchDTO) { 2 | if (watchDTO.getSocialWatchType() == "POST" && watchDTO.getNumberWatchers() < 3 ) { 3 | log.erro('O post "' + watchDTO.getText() + '" do autor ' + watchDTO.getPostAuthor() + ' deixou de ser polemico'); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /templates/workflowEvents/beforeTaskSave.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {string} colleagueId Matrícula do usuário corrente 5 | * @param {number} nextSequenceId 6 | * @param {java.util.List} userList Lista de matrículas de usuários destino 7 | */ 8 | function beforeTaskSave(colleagueId, nextSequenceId, userList) { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /resources/images/dark/preview.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /templates/workflowEvents/beforeTaskComplete.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {string} colleagueId Matrícula do usuário corrente 5 | * @param {number} nextSequenceId 6 | * @param {java.util.List} userList Lista de matrículas de usuários destino 7 | */ 8 | function beforeTaskComplete(colleagueId, nextSequenceId, userList) { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /templates/createMechanism.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {WorkflowProcess} process Processo 5 | * @param {Colleague} colleague Colleague 6 | * @returns {java.util.ArrayList} 7 | */ 8 | function resolve(process, colleague) { 9 | 10 | var userList = new java.util.ArrayList(); 11 | 12 | 13 | 14 | return userList; 15 | } 16 | -------------------------------------------------------------------------------- /templates/workflowEvents/afterTaskComplete.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {string} colleagueId Matrícula do usuário corrente 5 | * @param {number} nextSequenceId 6 | * @param {java.util.ArrayList} userList Matrículas de usuários destino 7 | */ 8 | function afterTaskComplete(colleagueId, nextSequenceId, userList) { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /templates/workflowEvents/afterTaskSave.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {string} colleagueId Matrícula do Usuário 5 | * @param {number} nextSequenceId Próxima Atividade 6 | * @param {java.util.ArrayList} userList Matrículas de usuários destino 7 | */ 8 | function afterTaskSave(colleagueId, nextSequenceId, userList) { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /templates/globalEvents/beforeCommunityLeave.txt: -------------------------------------------------------------------------------- 1 | function beforeCommunityLeave(companyId, relation) { 2 | if (relation.getCommunity().getAlias() == "eventos") { 3 | throw "Não é permitido deixar essa comunidade"; 4 | } 5 | log.info("beforeCommunityLeave Social Alias: " + relation.getSocial().getAlias() + " Community Alias: " + relation.getCommunity().getAlias()); 6 | } 7 | -------------------------------------------------------------------------------- /src/models/ServerDTO.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Representa a configuração de um Servidor 3 | */ 4 | export interface ServerDTO { 5 | id: string; 6 | name: string; 7 | host: string; 8 | ssl: boolean; 9 | port: number; 10 | username: string; 11 | password: string; 12 | userCode: string; 13 | confirmExporting: boolean; 14 | companyId: number; 15 | } 16 | -------------------------------------------------------------------------------- /resources/images/dark/edit.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /templates/globalEvents/beforeCommunityParticipation.txt: -------------------------------------------------------------------------------- 1 | function beforeCommunityParticipation(companyId, relation) { 2 | if (relation.getCommunity().getAlias() == "economia") { 3 | throw "Comunidade temporariamente indisponível"; 4 | } 5 | log.info("beforeCommunityParticipation Social Alias: " + relation.getSocial().getAlias() + " Community Alias: " + relation.getCommunity().getAlias()); 6 | } 7 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature 3 | about: Sugira uma ideia para o projeto 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Descreva a melhoria** 11 | Uma descrição clara e concisa da melhoria. 12 | 13 | **Ganhos** 14 | Descreva os ganhos que essa melhoria trará. 15 | 16 | **Contexto adicional** 17 | Acrescentar aqui qualquer outro contexto sobre a melhoria. 18 | -------------------------------------------------------------------------------- /resources/images/light/edit.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /templates/globalEvents/beforeSocialShare.txt: -------------------------------------------------------------------------------- 1 | function beforeSocialShare(companyId, share) { 2 | /* 3 | var lastUpd = share.getSociable().getLastUpdateDate().getTime(); 4 | log.info("lastUpd: " + lastUpd); 5 | 6 | var daysAgo = new Date(); 7 | daysAgo.setDate(daysAgo.getDate()-3); 8 | 9 | log.info("daysAgo: " + daysAgo); 10 | 11 | if (lastUpd < daysAgo) { 12 | throw "You could not share old socials (more than 3 days old)"; 13 | } 14 | */ 15 | } 16 | -------------------------------------------------------------------------------- /resources/images/dark/trash.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /templates/globalEvents/afterDocumentRemovePermanently.txt: -------------------------------------------------------------------------------- 1 | function afterDocumentRemovePermanently() { 2 | 3 | // Exemplo implementação 4 | 5 | var doc = getValue("WKDocument"); 6 | var user = getValue("WKUser"); 7 | var company = getValue("WKCompany"); 8 | 9 | log.info("Usuário Logado: " + user); 10 | log.info("Empresa: " + company); 11 | 12 | log.info("Número do documento: " + doc.getDocumentId() + " - Versão" + doc.getVersion()); */ 13 | } 14 | -------------------------------------------------------------------------------- /templates/globalEvents/beforeDocumentRemovePermanently.txt: -------------------------------------------------------------------------------- 1 | function beforeDocumentRemovePermanently() { 2 | 3 | // Exemplo implementação 4 | 5 | var doc = getValue("WKDocument"); 6 | var user = getValue("WKUser"); 7 | var company = getValue("WKCompany"); 8 | 9 | log.info("Usuário Logado: " + user); 10 | log.info("Empresa: " + company); 11 | 12 | log.info("Número do documento: " + doc.getDocumentId() + " - Versão" + doc.getVersion()); 13 | } 14 | -------------------------------------------------------------------------------- /templates/widget/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 30 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/models/DatasetStructureDTO.ts: -------------------------------------------------------------------------------- 1 | export interface DatasetStructureDTO { 2 | datasetPK: { 3 | companyId: number; 4 | datasetId: string; 5 | }; 6 | datasetDescription: string; 7 | datasetImpl: string; 8 | datasetBuilder: string; 9 | serverOffline: boolean; 10 | mobileCache: boolean; 11 | lastReset: number; 12 | lastRemoteSync: number; 13 | type: string; 14 | mobileOffline: boolean; 15 | updateIntervalTimestamp: number; 16 | } 17 | -------------------------------------------------------------------------------- /templates/globalEvents/onNotify.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {java.util.ArrayList} subject Assunto do e-mail. Exemplo: subject.add("ASSUNTO"); 5 | * @param {java.util.ArrayList} receivers Lista de e-mails destinatários 6 | * @param {string} template Nome do Template de E-Mail utilizado 7 | * @param {java.util.HashMap} params Mapa dos parâmetros utilizados no e-mail 8 | */ 9 | function onNotify(subject, receivers, template, params) { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /resources/images/light/preview.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": false // set this to true to hide the "out" folder with the compiled JS files 5 | }, 6 | "search.exclude": { 7 | "out": true // set this to false to include "out" folder in search results 8 | }, 9 | // Turn off tsc task auto detection since we have the necessary tasks as npm scripts 10 | "typescript.tsc.autoDetect": "off" 11 | } 12 | -------------------------------------------------------------------------------- /templates/widget/src/main/webapp/resources/js/widgetname.js: -------------------------------------------------------------------------------- 1 | var widgetname = SuperWidget.extend({ 2 | 3 | //variáveis da widget 4 | variavelNumerica: null, 5 | variavelCaracter: null, 6 | 7 | //método iniciado quando a widget é carregada 8 | init() { 9 | }, 10 | 11 | //BIND de eventos 12 | bindings: { 13 | local: { 14 | 'execute': ['click_executeAction'] 15 | }, 16 | global: {} 17 | }, 18 | 19 | executeAction(htmlElement, event) { 20 | } 21 | }); 22 | -------------------------------------------------------------------------------- /src/models/AttributionMechanismDTO.ts: -------------------------------------------------------------------------------- 1 | export interface AttributionMechanismDTO { 2 | attributionMecanismPK: { 3 | companyId: number; 4 | attributionMecanismId: string; 5 | }, 6 | assignmentType: number; // 1 7 | controlClass: string; // "com.datasul.technology.webdesk.workflow.assignment.customization.CustomAssignmentImpl", 8 | preSelectionClass: null; 9 | configurationClass: string; // "" 10 | name: string; 11 | description: string; 12 | attributionMecanismDescription: string; 13 | } 14 | -------------------------------------------------------------------------------- /templates/globalEvents/afterReleaseProcessVersion.txt: -------------------------------------------------------------------------------- 1 | function afterReleaseProcessVersion(processXML) { 2 | 3 | // Exemplo de como obter dados do processo 4 | 5 | var pdv = getValue("ProcessDefinitionVersionDto"); 6 | 7 | var processInfo = "\n### Nova versde processo liberada: ###"; 8 | processInfo += "\n User: " + getValue("WKUser"); 9 | processInfo += "\n processDescription: " + pdv.getProcessDescription(); 10 | processInfo += "\n processId: " + pdv.getProcessId(); 11 | processInfo += "\n version: " + pdv.getVersion(); 12 | 13 | log.info(processInfo + "\n"); 14 | } 15 | -------------------------------------------------------------------------------- /templates/globalEvents/beforeCreateUser.txt: -------------------------------------------------------------------------------- 1 | function beforeCreateUser(user) { 2 | // Verifica se a senha informada atende os requisitos m 3 | var passwordPattern = "((?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%]).{8,16})"; 4 | 5 | if (!user.getPassword().matches(passwordPattern)) { 6 | throw "A senha do usuário não atendeu os requisitos mínimos"; 7 | } 8 | 9 | // Adiciona um dado adicional ao usuário informando a sua data de criação 10 | var dateFormat = new java.text.SimpleDateFormat("dd/MM/yyyy HH:mm:ss"); 11 | user.putData("CreationDate", dateFormat.format(new Date())); 12 | } 13 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "parserOptions": { 5 | "ecmaVersion": 6, 6 | "sourceType": "module" 7 | }, 8 | "plugins": [ 9 | "@typescript-eslint" 10 | ], 11 | "rules": { 12 | "@typescript-eslint/naming-convention": "warn", 13 | "@typescript-eslint/semi": "warn", 14 | "curly": "warn", 15 | "eqeqeq": "warn", 16 | "no-throw-literal": "warn", 17 | "semi": "off" 18 | }, 19 | "ignorePatterns": [ 20 | "**/*.d.ts" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /src/services/GlobalStorageService.ts: -------------------------------------------------------------------------------- 1 | import { ExtensionContext } from "vscode"; 2 | import { ServerDTO } from "../models/ServerDTO"; 3 | 4 | export class GlobalStorageService { 5 | 6 | static getLastParentDocumentId(context: ExtensionContext, server: ServerDTO): string { 7 | return context.globalState.get(server.id + "_lastParentDocumentId") || "2"; 8 | } 9 | 10 | static updateLastParentDocumentId(context: ExtensionContext, server: ServerDTO, newValue: string) { 11 | context.globalState.update(server.id + "_lastParentDocumentId", newValue); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /resources/images/dark/refresh.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /resources/images/light/trash.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /resources/images/dark/database.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "lib": [ 7 | "es6" 8 | ], 9 | "sourceMap": true, 10 | "rootDir": "src", 11 | "strict": true /* enable all strict type-checking options */ 12 | /* Additional Checks */ 13 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 14 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 15 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 16 | }, 17 | "exclude": [ 18 | "node_modules", 19 | ".vscode-test" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /resources/images/dark/server-environment.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug 3 | about: Reporte erros para nos ajudar a melhorar 4 | title: "[BUG]" 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Descreva o erro** 11 | Uma descrição clara e concisa do problema. 12 | 13 | **Para reproduzir** 14 | Etapas para reproduzir o comportamento: 15 | 1. Vá até '...' 16 | 2. Clique em '....' 17 | 3. Desça até '....' 18 | 4. Veja o erro 19 | 20 | **Resultado esperado** 21 | Uma descrição clara e concisa do que se esperava que acontecesse. 22 | 23 | **Screenshots** 24 | Se aplicável, adicione screenshots para ajudar a explicar o seu problema. 25 | 26 | **Contexto adicional** 27 | Acrescentar aqui qualquer outro contexto sobre o problema. 28 | -------------------------------------------------------------------------------- /templates/globalEvents/afterDocumentRestore.txt: -------------------------------------------------------------------------------- 1 | function afterDocumentRestore() { 2 | 3 | // Exemplo implementação 4 | 5 | var doc = getValue("WKDocument"); 6 | var subject = getValue("WKSubject"); 7 | var listApprover = getValue("WKListApprover"); 8 | var listSeg = getValue("WKListSecurity"); 9 | var listRelated = getValue("WKListRelatedDocument"); 10 | var user = getValue("WKUser"); 11 | var company = getValue("WKCompany"); 12 | 13 | log.info("Usuário Logado: " + user); 14 | log.info("Empresa: " + company); 15 | 16 | log.info("Número do documento: " + doc.getDocumentId() + " - Versão" + doc.getVersion()); 17 | 18 | log.info("Assunto: " + subject); 19 | } 20 | -------------------------------------------------------------------------------- /templates/globalEvents/beforeDocumentRestore.txt: -------------------------------------------------------------------------------- 1 | function beforeDocumentRestore() { 2 | 3 | //Exemplo implementa 4 | 5 | var doc = getValue("WKDocument"); 6 | var subject = getValue("WKSubject"); 7 | var listApprover = getValue("WKListApprover"); 8 | var listSeg = getValue("WKListSecurity"); 9 | var listRelated = getValue("WKListRelatedDocument"); 10 | var user = getValue("WKUser"); 11 | var company = getValue("WKCompany"); 12 | 13 | log.info("Usuário Logado: " + user); 14 | log.info("Empresa: " + company); 15 | 16 | log.info("Número do documento: " + doc.getDocumentId() + " - Versão" + doc.getVersion()); 17 | 18 | log.info("Assunto: " + subject); 19 | } 20 | -------------------------------------------------------------------------------- /resources/images/light/refresh.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /templates/createDataset.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @param {string[]} fields Campos Solicitados 5 | * @param {Constraint[]} constraints Filtros 6 | * @param {string[]} sorts Campos da Ordenação 7 | * @returns {Dataset} 8 | */ 9 | function createDataset(fields, constraints, sorts) { 10 | var dataset = DatasetBuilder.newDataset(); 11 | 12 | return dataset; 13 | } 14 | 15 | /** 16 | * 17 | */ 18 | function defineStructure() { 19 | 20 | } 21 | 22 | /** 23 | * 24 | * 25 | * @param {number} lastSyncDate 26 | */ 27 | function onSync(lastSyncDate) { 28 | 29 | } 30 | 31 | /** 32 | * 33 | * 34 | * @param user 35 | * @returns {DatasetMobileSync} 36 | */ 37 | function onMobileSync(user) { 38 | 39 | } 40 | -------------------------------------------------------------------------------- /templates/globalEvents/beforeDownloadContent.txt: -------------------------------------------------------------------------------- 1 | function beforeDownloadContent(documentId) { 2 | //Exemplo de Implementação 3 | 4 | var companyId = getValue("WKCompany"); 5 | var c1 = DatasetFactory.createConstraint( "documentPK.documentId", documentId, documentId, ConstraintType.MUST); 6 | var c2 = DatasetFactory.createConstraint( "documentPK.companyId", companyId, companyId, ConstraintType.MUST); 7 | var constraints = new Array(c1, c2); 8 | var ds = DatasetFactory.getDataset("document", null, constraints, null); 9 | 10 | if (ds != null && ds.rowsCount > 0) { 11 | var parent = ds.getValue(0, "parentDocumentId"); 12 | 13 | if (parent == 43) { 14 | throw "Download não permitido!"; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /templates/widget/src/main/resources/application.info: -------------------------------------------------------------------------------- 1 | application.type=widget 2 | application.code=widgetname 3 | application.title=widgetname 4 | application.description=widgetname 5 | application.category=SYSTEM 6 | application.icon=icon.png 7 | application.renderer=freemarker 8 | developer.code=FLUIG-VSCODE-EXTENSION 9 | developer.name=FLUIG-VSCODE-EXTENSION 10 | developer.url=https://github.com/fluiggers/fluig-vscode-extension 11 | application.uiwidget=true 12 | application.mobileapp=false 13 | application.version=0.1.0 14 | view.file=view.ftl 15 | edit.file=edit.ftl 16 | locale.file.base.name=widgetname 17 | application.resource.js.1=/resources/js/widgetname.js 18 | application.resource.css.2=/resources/css/widgetname.css 19 | -------------------------------------------------------------------------------- /templates/form.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 | 16 |
17 |
18 | 19 | 20 | -------------------------------------------------------------------------------- /templates/workflowEvents/calculateAgreement.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @example 4 | * log.info("Consenso Atual: " + agreementData.get("currentPercentage")); 5 | * log.info("Atividade Destino Atual: " + agreementData.get("currentDestState")); 6 | * log.info("Usuario Destino Atual: " + agreementData.get("currentDestUsers")); 7 | * 8 | * //Altera o consenso 9 | * agreementData.put("currentPercentage", 100); 10 | * agreementData.put("currentDestState", 2); 11 | * agreementData.put("currentDestUsers", "marcos"); 12 | * 13 | * @param {number} currentState Atividade que terá o consenso alterado 14 | * @param {java.util.Map} agreementData 15 | */ 16 | function calculateAgreement(currentState, agreementData) { 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/models/FormDTO.ts: -------------------------------------------------------------------------------- 1 | import { AttachmentArrayDTO } from "./AttachmentArrayDTO"; 2 | import { CustomizationEventsArrayDTO } from "./CustomizationEventsArrayDTO"; 3 | import { FormGeneralInfoDto } from "./FormGeneralInfoDto"; 4 | 5 | export interface FormDTO { 6 | username: string; 7 | password: string; 8 | companyId: number; 9 | parentDocumentId?: number; 10 | documentId?: number; 11 | publisherId: string; 12 | documentDescription?: string; 13 | cardDescription?: string; 14 | datasetName: string; 15 | Attachments: AttachmentArrayDTO; 16 | customEvents: CustomizationEventsArrayDTO; 17 | persistenceType?: number; 18 | generalInfo?: FormGeneralInfoDto; 19 | descriptionField?: string; 20 | } 21 | -------------------------------------------------------------------------------- /src/services/UserService.ts: -------------------------------------------------------------------------------- 1 | import { ServerDTO } from "../models/ServerDTO"; 2 | import { LoginService } from "./LoginService"; 3 | import { UtilsService } from "./UtilsService"; 4 | 5 | export class UserService { 6 | 7 | /** 8 | * Obter informações do usuário 9 | */ 10 | public static async getUser(server: ServerDTO): Promise { 11 | const url = UtilsService.getRestUrl( 12 | server, 13 | "/portal/api/rest/wcmservice/rest/user/", 14 | "findUserByLogin", 15 | { "login": server.username } 16 | ); 17 | 18 | return fetch(url, { 19 | headers: { 'Cookie': await LoginService.loginAndGetCookies(server) } 20 | }).then(r => r.json()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /templates/globalEvents/beforeUpdateUser.txt: -------------------------------------------------------------------------------- 1 | function beforeUpdateUser(user) { 2 | // Verifica se foi alterada a senha do usuário 3 | if (user.getPassword() != null) { 4 | // Caso a senha tenha sido alterada verifica se ela atende os requisitos mínimos 5 | var passwordPattern = "((?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%]).{8,16})"; 6 | 7 | if (!user.getPassword().matches(passwordPattern)) { 8 | throw "A senha do usuário não atendeu os requisitos mínimos" 9 | } 10 | } 11 | 12 | // Adiciona um dado adicional ao usuário informando a data de atualização 13 | var dateFormat = new java.text.SimpleDateFormat("dd/MM/yyyy HH:mm:ss"); 14 | user.putData("LastUpdateDate", dateFormat.format(new Date())); 15 | } 16 | -------------------------------------------------------------------------------- /resources/images/light/database.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /resources/images/light/server-environment.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /templates/globalEvents/onDisplayTasksSummary.txt: -------------------------------------------------------------------------------- 1 | function onDisplayTasksSummary(resumeTasks) { 2 | // Exemplo de implementação 3 | 4 | log.info("--------------------------------------"); 5 | 6 | log.dir(resumeTasks); 7 | 8 | log.info("--------------------------------------"); 9 | 10 | log.info("WKUser: " + getValue("WKUser")); 11 | log.info("WKUserLocale: " + getValue("WKUserLocale")); 12 | log.info("WKCompany: " + getValue("WKCompany")); 13 | log.info("taskUserId: " + getValue("taskUserId")); 14 | log.info("--------------------------------------"); 15 | 16 | resumeTasks.expiredTasks = 10; 17 | resumeTasks.openTasks = 20; 18 | resumeTasks.myRequests = 30; 19 | resumeTasks.toApprover = 40; 20 | resumeTasks.myDocuments = 50; 21 | resumeTasks.checkout = 60; 22 | 23 | log.info("--------------------------------------"); 24 | 25 | log.dir(resumeTasks); 26 | 27 | log.info("--------------------------------------"); 28 | } 29 | -------------------------------------------------------------------------------- /templates/globalEvents/afterDocumentRemove.txt: -------------------------------------------------------------------------------- 1 | function afterDocumentRemove() { 2 | 3 | // Exemplo implementação 4 | 5 | var doc = getValue("WKDocument"); 6 | var subject = getValue("WKSubject"); 7 | var listApprover = getValue("WKListApprover"); 8 | var listSeg = getValue("WKListSecurity"); 9 | var listRelated = getValue("WKListRelatedDocument"); 10 | var user = getValue("WKUser"); 11 | var company = getValue("WKCompany"); 12 | 13 | log.info("Usuário Logado: " + user); 14 | log.info("Empresa: " + company); 15 | 16 | log.info("Número do documento: " + doc.getDocumentId() + " - Versão" + doc.getVersion()); 17 | 18 | if (listRelated != null) { 19 | log.info("Os seguintes documentos estão relacionados a este documentos: "); 20 | 21 | for (j = 0; j < listRelated.size(); j++) { 22 | log.info("Nr. documento: " + listRelated.get(j).getRelatedDocumentId()); 23 | } 24 | } 25 | 26 | log.info("Assunto: " + subject); 27 | } 28 | -------------------------------------------------------------------------------- /templates/globalEvents/beforeDocumentRemove.txt: -------------------------------------------------------------------------------- 1 | function beforeDocumentRemove() { 2 | 3 | // Exemplo implementação 4 | 5 | var doc = getValue("WKDocument"); 6 | var subject = getValue("WKSubject"); 7 | var listApprover = getValue("WKListApprover"); 8 | var listSeg = getValue("WKListSecurity"); 9 | var listRelated = getValue("WKListRelatedDocument"); 10 | var user = getValue("WKUser"); 11 | var company = getValue("WKCompany"); 12 | 13 | log.info("Usuário Logado: " + user); 14 | log.info("Empresa: " + company); 15 | 16 | log.info("Número do documento: " + doc.getDocumentId() + " - Versão" + doc.getVersion()); 17 | 18 | if (listRelated != null) { 19 | log.info("Os seguintes documentos estão relacionados a este documentos: "); 20 | 21 | for (j = 0; j < listRelated.size(); j++) { 22 | log.info("Nr. documento: " + listRelated.get(j).getRelatedDocumentId()); 23 | } 24 | } 25 | 26 | log.info("Assunto: " + subject); 27 | } 28 | -------------------------------------------------------------------------------- /src/extensions/TemplateExtension.ts: -------------------------------------------------------------------------------- 1 | import { ExtensionContext, Uri } from 'vscode'; 2 | import { TemplateService } from "../services/TemplateService"; 3 | 4 | export class TemplateExtension { 5 | 6 | public static activate(context: ExtensionContext): void { 7 | TemplateService.templatesUri = Uri.joinPath(context.extensionUri, 'dist', 'templates'); 8 | TemplateService.formEventsUri = Uri.joinPath(TemplateService.templatesUri, 'formEvents'); 9 | TemplateService.workflowEventsUri = Uri.joinPath(TemplateService.templatesUri, 'workflowEvents'); 10 | TemplateService.globalEventsUri = Uri.joinPath(TemplateService.templatesUri, 'globalEvents'); 11 | TemplateService.formEventsNames = TemplateService.getTemplatesNameFromPath(TemplateService.formEventsUri); 12 | TemplateService.workflowEventsNames = TemplateService.getTemplatesNameFromPath(TemplateService.workflowEventsUri); 13 | TemplateService.globalEventsNames = TemplateService.getTemplatesNameFromPath(TemplateService.globalEventsUri); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Run Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "args": [ 13 | "--extensionDevelopmentPath=${workspaceFolder}" 14 | ], 15 | "outFiles": [ 16 | "${workspaceFolder}/dist/**/*.js" 17 | ], 18 | "preLaunchTask": "${defaultBuildTask}" 19 | }, 20 | { 21 | "name": "Extension Tests", 22 | "type": "extensionHost", 23 | "request": "launch", 24 | "args": [ 25 | "--extensionDevelopmentPath=${workspaceFolder}", 26 | "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" 27 | ], 28 | "outFiles": [ 29 | "${workspaceFolder}/out/test/**/*.js" 30 | ], 31 | "preLaunchTask": "npm: test-watch" 32 | } 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Bruno Gasparetto 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | import { ExtensionContext, workspace } from "vscode"; 2 | import { TemplateExtension } from "./extensions/TemplateExtension"; 3 | import { LibraryExtension } from "./extensions/LibraryExtension"; 4 | import { DatasetExtension } from "./extensions/DatasetExtension"; 5 | import { FormExtension } from "./extensions/FormExtension"; 6 | import { WidgetExtension } from "./extensions/WidgetExtension"; 7 | import { WorkflowExtension } from "./extensions/WorkflowExtension"; 8 | import { GlobalEventExtension } from "./extensions/GlobalEventExtension"; 9 | import { ServerExtension } from "./extensions/ServerExtension"; 10 | 11 | export function activate(context: ExtensionContext) { 12 | if (!workspace.workspaceFolders) { 13 | throw new Error("É necessário estar em Workspace / Diretório."); 14 | } 15 | 16 | TemplateExtension.activate(context); 17 | LibraryExtension.activate(context); 18 | DatasetExtension.activate(context); 19 | FormExtension.activate(context); 20 | WidgetExtension.activate(context); 21 | WorkflowExtension.activate(context); 22 | GlobalEventExtension.activate(context); 23 | ServerExtension.activate(context); 24 | } 25 | 26 | export function deactivate() { 27 | } 28 | -------------------------------------------------------------------------------- /templates/globalEvents/beforeDocumentViewer.txt: -------------------------------------------------------------------------------- 1 | function beforeDocumentViewer() { 2 | 3 | // Exemplo implementação 4 | 5 | var doc = getValue("WKDocument"); 6 | var company = getValue("WKCompany"); 7 | var ds 8 | 9 | try { 10 | var c1 = DatasetFactory.createConstraint( "allocatedDocumentPK.companyId", company, company, ConstraintType.MUST); 11 | var c2 = DatasetFactory.createConstraint("allocatedDocumentPK.sourceDocument", doc.getDocumentId(), doc.getDocumentId(), ConstraintType.MUST); 12 | var c3 = DatasetFactory.createConstraint("allocatedDocumentPK.sourceVersion", doc.getVersion(),doc.getVersion(), ConstraintType.MUST); 13 | var c4 = DatasetFactory.createConstraint("active", "true","true",ConstraintType.MUST); 14 | var constraints = new Array(c1, c2, c3, c4); 15 | 16 | ds = DatasetFactory.getDataset("allocatedDocument", null, constraints, null); 17 | } catch (e) { 18 | log.error("Erro ao tentar recuperar o documento em CheckOut: " + e.message); 19 | } 20 | 21 | if (ds!=null && ds.rowsCount>0) { 22 | throw "Este documento estem Check-out e não pode ser visualizado. " 23 | + "Foi gerado o documento " + ds.getValue(0,"allocatedDocumentPK.destinationDocument") 24 | + " que está sob responsabilidade do colaborador com matrícula "+ ds.getValue(0,"colleagueId") 25 | ; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/services/TemplateService.ts: -------------------------------------------------------------------------------- 1 | import { Uri } from 'vscode'; 2 | import { globSync } from "glob"; 3 | import { basename } from "path"; 4 | 5 | export class TemplateService { 6 | 7 | public static templatesUri: Uri; 8 | public static formEventsUri: Uri; 9 | public static workflowEventsUri: Uri; 10 | public static globalEventsUri: Uri; 11 | 12 | public static formEventsNames: string[]; 13 | public static workflowEventsNames: string[]; 14 | public static globalEventsNames: string[]; 15 | 16 | /** 17 | * Pega o nome dos templates de determinado diretório 18 | * 19 | * @param templatesUri Diretório onde estão os templates 20 | * @returns Nome dos arquivos sem a extensão 21 | */ 22 | static getTemplatesNameFromPath(templatesUri: Uri): string[] { 23 | return globSync(Uri.joinPath(templatesUri, '*.txt').path) 24 | .map(filename => basename(filename, ".txt")) 25 | .sort((a, b) => a.localeCompare(b)) 26 | ; 27 | } 28 | 29 | /** 30 | * Cria o conteúdo de evento/função compartilhada 31 | * 32 | * @param functionName Nome da Função 33 | * @returns Definição da função 34 | */ 35 | static createEmptyFunction(functionName: string): string { 36 | return `/** 37 | * 38 | * 39 | */ 40 | function ${functionName}() { 41 | 42 | } 43 | 44 | `; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /templates/globalEvents/beforeDeactivateUser.txt: -------------------------------------------------------------------------------- 1 | function beforeDeactivateUser(login) { 2 | // Instância um cliente da API pdo Fluig. 3 | // O usuário aplicativo utilizado precisa ser um administrador do Fluig 4 | var consumer = oauthUtil.getNewAPIConsumer( 5 | "e3fe3d72-bfcc-4552-8c9b-93c66531dab9", 6 | "6bd0591b-73d8-4a9e-a161-d54dd92d3172-5a21991e-453f-4ea1-b80c-f42d4c57759d", 7 | "11a419dd-0c8a-4388-bd32-d66319bd750b", 8 | "fd2b53a4-b43d-4118-9725-68abaa1b41a9ee584784-73b2-454b-942f-5e07ad114234" 9 | ); 10 | 11 | // Verifica se o usuário que esta sendo desativado é moderador de alguma comunidade 12 | var moderateCommunities = []; 13 | var communities = JSON.parse(consumer.get("/public/social/community/listCommunities")).content; 14 | 15 | for (var i in communities) { 16 | var isModerator = JSON.parse(consumer.get("/public/social/community/isCommunityModerator/" + communities[i].alias + "/" + login)).content; 17 | 18 | if (isModerator) { 19 | moderateCommunities.push(communities[i].name); 20 | } 21 | } 22 | 23 | // Caso o usuário seja moderador de alguma comunidade lança uma exceção informando que 24 | // o usuário moderador de comunidades e não pode ser desativado 25 | if (moderateCommunities.length > 0) { 26 | throw "O usuário " + login + " não pode ser desativado por ser moderador nas comunidades: " + moderateCommunities.join(", ") + "."; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/services/CryptoService.ts: -------------------------------------------------------------------------------- 1 | import { env } from 'vscode'; 2 | import { randomBytes, scryptSync, createCipheriv, createDecipheriv } from 'crypto'; 3 | 4 | const algorithm = 'aes-256-cbc'; 5 | const keyLength = 32; 6 | const saltLength = 16; 7 | const ivLength = 16; 8 | 9 | export class CryptoService { 10 | public static encrypt(text: string): string { 11 | const iv = randomBytes(ivLength); 12 | const salt = randomBytes(saltLength); 13 | const secretKey = scryptSync(env.machineId, salt, keyLength); 14 | const cipher = createCipheriv(algorithm, secretKey, iv); 15 | const encrypted = cipher.update(Buffer.from(text, "utf8")); 16 | 17 | return Buffer.from(JSON.stringify({ 18 | iv: iv.toString('hex'), 19 | salt: salt.toString("hex"), 20 | text: Buffer.concat([encrypted, cipher.final()]).toString('hex') 21 | })).toString("base64"); 22 | } 23 | 24 | public static decrypt(encrypted: string): string { 25 | const data = JSON.parse(Buffer.from(encrypted, "base64").toString("utf8")); 26 | const secretKey = scryptSync(env.machineId, Buffer.from(data.salt, "hex"), keyLength); 27 | const decipher = createDecipheriv(algorithm, secretKey, Buffer.from(data.iv, "hex")); 28 | const decrypted = decipher.update(Buffer.from(data.text, "hex")); 29 | 30 | return Buffer.concat([decrypted, decipher.final()]).toString("utf8"); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /templates/globalEvents/beforeDocumentPublisher.txt: -------------------------------------------------------------------------------- 1 | function beforeDocumentPublisher() { 2 | 3 | // Exemplo implementação 4 | 5 | var doc = getValue("WKDocument"); 6 | var subject = getValue("WKSubject"); 7 | var listApprover = getValue("WKListApprover"); 8 | var listSeg = getValue("WKListSecurity"); 9 | var listRelated = getValue("WKListRelatedDocument"); 10 | var state = getValue("WKState"); 11 | var user = getValue("WKUser"); 12 | var company = getValue("WKCompany"); 13 | 14 | log.info("Usuário Logado: " + user); 15 | log.info("Empresa: " + company); 16 | 17 | log.info("Número do documento: " + doc.getDocumentId() + " - Versão" + doc.getVersion()); 18 | 19 | if (listApprover != null) { 20 | for (j = 0; j < listApprover.size(); j++) { 21 | if (listApprover.get(j).getColleagueId().equals("adm")) { 22 | throw "O usuadm npode ser aprovador de documentos"; 23 | } 24 | } 25 | } 26 | 27 | if (listSeg != null) { 28 | for (j = 0; j < listSeg.size(); j++) { 29 | if (listSeg.get(j).getAttributionValue().equals("cvd")) { 30 | throw "O usucvd npode estar na segurande documentos"; 31 | } 32 | } 33 | } 34 | 35 | if (listRelated != null) { 36 | log.info("Os seguintes documentos estão relacionados a este documento: "); 37 | for (j = 0; j < listRelated.size(); j++) { 38 | log.info("Nr. documento: " + listRelated.get(j).getRelatedDocumentId()); 39 | } 40 | } 41 | log.info("Assunto: " + subject); 42 | log.info("Estado: " + state); 43 | } 44 | -------------------------------------------------------------------------------- /src/extensions/WidgetExtension.ts: -------------------------------------------------------------------------------- 1 | import { ExtensionContext, commands, Uri, window } from 'vscode'; 2 | import { WidgetService } from "../services/WidgetService"; 3 | 4 | export class WidgetExtension { 5 | public static activate(context: ExtensionContext): void { 6 | context.subscriptions.push(commands.registerCommand( 7 | "fluiggers-fluig-vscode-extension.newWidget", 8 | WidgetService.create 9 | )); 10 | 11 | context.subscriptions.push(commands.registerCommand( 12 | "fluiggers-fluig-vscode-extension.exportWidget", 13 | function (fileUri: Uri) { 14 | // Ativado pela Tecla Atalho 15 | if (!fileUri) { 16 | if (!window.activeTextEditor) { 17 | window.showErrorMessage("Não há editor de texto ativo na Widget"); 18 | return; 19 | } 20 | fileUri = window.activeTextEditor.document.uri; 21 | } 22 | 23 | WidgetService.export(fileUri); 24 | } 25 | )); 26 | 27 | context.subscriptions.push(commands.registerCommand( 28 | "fluiggers-fluig-vscode-extension.importWidget", 29 | WidgetService.import 30 | )); 31 | 32 | context.subscriptions.push(commands.registerCommand( 33 | "fluiggers-fluig-vscode-extension.exportFluiggersWidget", 34 | WidgetService.exportFluiggersWidget 35 | )); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | //@ts-check 2 | 3 | 'use strict'; 4 | 5 | const path = require('path'); 6 | 7 | /**@type {import('webpack').Configuration}*/ 8 | const config = { 9 | target: 'node', // vscode extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/ 10 | mode: 'none', // this leaves the source code as close as possible to the original (when packaging we set this to 'production') 11 | 12 | entry: './src/extension.ts', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/ 13 | output: { 14 | // the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/ 15 | path: path.resolve(__dirname, 'dist'), 16 | filename: 'extension.js', 17 | libraryTarget: 'commonjs2' 18 | }, 19 | devtool: 'nosources-source-map', 20 | externals: { 21 | vscode: 'commonjs vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/ 22 | }, 23 | resolve: { 24 | // support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader 25 | extensions: ['.ts', '.js'] 26 | }, 27 | module: { 28 | rules: [ 29 | { 30 | test: /\.ts$/, 31 | exclude: /node_modules/, 32 | use: [ 33 | { 34 | loader: 'ts-loader' 35 | } 36 | ] 37 | } 38 | ] 39 | } 40 | }; 41 | module.exports = config; -------------------------------------------------------------------------------- /templates/globalEvents/beforeWatchContent.txt: -------------------------------------------------------------------------------- 1 | function beforeWatchContent(companyId, watchDTO) { 2 | if (watchDTO.getSocialWatchType() == "DOCUMENT") { 3 | //var objClass = "com.totvs.technology.social.document.6"; 4 | var objClass = watchDTO.getObjectClass(); 5 | var patt = new RegExp(/\d+/); 6 | var documentId = patt.exec(objClass); 7 | var documentVersion = watchDTO.getObjectId(); 8 | var doc = getValue("WKDocument"); 9 | var company = companyId; 10 | var ds; 11 | 12 | try { 13 | var c1 = DatasetFactory.createConstraint("allocatedDocumentPK.companyId", company, company, ConstraintType.MUST); 14 | var c2 = DatasetFactory.createConstraint("allocatedDocumentPK.sourceDocument", documentId, documentId, ConstraintType.MUST); 15 | var c3 = DatasetFactory.createConstraint("allocatedDocumentPK.sourceVersion", documentVersion, documentVersion, ConstraintType.MUST); 16 | var c4 = DatasetFactory.createConstraint("active", "true", "true", ConstraintType.MUST); 17 | var constraints = new Array(c1, c2, c3, c4); 18 | 19 | ds = DatasetFactory.getDataset("allocatedDocument", null, constraints, null); 20 | } catch (e) { 21 | log.error("Erro ao tentar recuperar o documento em CheckOut: " + e.message); 22 | } 23 | 24 | if (ds != null && ds.rowsCount > 0) { 25 | throw "Sua solicitação de notificação foi negada, pois o documento está em checkout."; 26 | } 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /templates/globalEvents/onDisplayTasks.txt: -------------------------------------------------------------------------------- 1 | function onDisplayTasks(tasks) { 2 | // Exemplo de implementação 3 | 4 | log.info("--------------------------------------"); 5 | 6 | log.dir(tasks); 7 | 8 | log.info("--------------------------------------"); 9 | log.info("WKUser: " + getValue("WKUser")); 10 | log.info("WKUserLocale: " + getValue("WKUserLocale")); 11 | log.info("WKCompany: " + getValue("WKCompany")); 12 | log.info("taskUserId: " + getValue("taskUserId")); 13 | log.info("taskType: " + getValue("taskType")); 14 | log.info("taskId: " + getValue("taskId")); 15 | log.info("filter: " + getValue("filter")); 16 | log.info("maxResult: " + getValue("maxResult")); 17 | log.info("page: " + getValue("page")); 18 | log.info("order: " + getValue("order")); 19 | log.info("offset: " + getValue("offset")); 20 | log.info("--------------------------------------"); 21 | 22 | //Insere na 1ª pagina da aba Tarefas a Concluir 23 | if (getValue("page") == 1 && getValue("taskType") == "open") { 24 | var newTask = new WorkflowTasksVO(); 25 | newTask.setCode("TOTVS"); 26 | newTask.setUrl("http://www.totvs.com"); 27 | newTask.setProcessDescription("Nova Tarefa"); 28 | newTask.setRequesterName("Joda Silva"); 29 | newTask.setStateDescription("Atividade 1"); 30 | newTask.setColleagueName("Ana Maria"); 31 | newTask.setStartDateProcess("07/09/2025"); 32 | newTask.setDateExpires("07/10/2025"); 33 | tasks.add(newTask); 34 | } 35 | 36 | log.info("--------------------------------------"); 37 | log.dir(tasks); 38 | log.info("--------------------------------------"); 39 | } 40 | -------------------------------------------------------------------------------- /src/extensions/ServerExtension.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import {DatasetItem, ServerItem, ServerItemProvider} from "../providers/ServerItemProvider"; 3 | import { ServerService } from '../services/ServerService'; 4 | 5 | export class ServerExtension { 6 | 7 | public static async activate(context: vscode.ExtensionContext): Promise { 8 | if (!(await ServerService.checkServerConfigVersion())) { 9 | throw new Error("Erro na versão do arquivo de configuração."); 10 | } 11 | 12 | const serverItemProvider = new ServerItemProvider(context); 13 | vscode.window.registerTreeDataProvider("fluiggers-fluig-vscode-extension.servers", serverItemProvider); 14 | 15 | context.subscriptions.push(vscode.commands.registerCommand( 16 | "fluiggers-fluig-vscode-extension.addServer", 17 | () => serverItemProvider.add() 18 | )); 19 | context.subscriptions.push(vscode.commands.registerCommand( 20 | "fluiggers-fluig-vscode-extension.refreshServer", 21 | () => serverItemProvider.refresh() 22 | )); 23 | context.subscriptions.push(vscode.commands.registerCommand( 24 | "fluiggers-fluig-vscode-extension.editServer", 25 | (serverItem: ServerItem) => serverItemProvider.update(serverItem) 26 | )); 27 | context.subscriptions.push(vscode.commands.registerCommand( 28 | "fluiggers-fluig-vscode-extension.deleteServer", 29 | (serverItem: ServerItem) => serverItemProvider.delete(serverItem) 30 | )); 31 | context.subscriptions.push(vscode.commands.registerCommand( 32 | "fluiggers-fluig-vscode-extension.datasetView", 33 | (datasetItem: DatasetItem) => serverItemProvider.datasetView(datasetItem) 34 | )); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/extensions/LibraryExtension.ts: -------------------------------------------------------------------------------- 1 | import { ExtensionContext, commands, Uri, window } from 'vscode'; 2 | import { UtilsService } from "../services/UtilsService"; 3 | import { createWriteStream } from "fs"; 4 | import { Readable } from "stream"; 5 | 6 | export class LibraryExtension { 7 | 8 | public static activate(context: ExtensionContext): void { 9 | context.subscriptions.push(commands.registerCommand( 10 | "fluiggers-fluig-vscode-extension.installDeclarationLibrary", 11 | LibraryExtension.installDeclarationLibrary 12 | )); 13 | } 14 | 15 | /** 16 | * Instala a última versão da bilioteca de tipos 17 | */ 18 | private static installDeclarationLibrary() { 19 | const workspaceUri = UtilsService.getWorkspaceUri(); 20 | 21 | Promise.all([ 22 | fetch("https://raw.githubusercontent.com/fluiggers/fluig-declaration-type/master/jsconfig.json"), 23 | fetch("https://raw.githubusercontent.com/fluiggers/fluig-declaration-type/master/fluig.d.ts") 24 | ]) 25 | .then(function ([jsConfig, fluigDeclarations]) { 26 | if (!jsConfig.ok || !jsConfig.body || !fluigDeclarations.ok || !fluigDeclarations.body) { 27 | throw new Error("Erro: Os arquivos da biblioteca de tipos não foram encontrados."); 28 | } 29 | 30 | const jsConfigWriter = createWriteStream(Uri.joinPath(workspaceUri, "jsconfig.json").fsPath); 31 | Readable.fromWeb(jsConfig.body).pipe(jsConfigWriter); 32 | 33 | const declarationsWriter = createWriteStream(Uri.joinPath(workspaceUri, "fluig.d.ts").fsPath); 34 | Readable.fromWeb(fluigDeclarations.body).pipe(declarationsWriter); 35 | 36 | window.showInformationMessage("A biblioteca de Declarações de Tipos foi instalada."); 37 | }) 38 | .catch(() => window.showErrorMessage("Erro ao baixar biblioteca do GitHub. Verifique sua conexão com a Internet")); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/models/Server.ts: -------------------------------------------------------------------------------- 1 | import { ServerDTO } from "./ServerDTO"; 2 | import { CryptoService } from "../services/CryptoService"; 3 | 4 | /** 5 | * Configuração do Servidor com criptografia da senha 6 | */ 7 | export class Server implements ServerDTO { 8 | public id: string = ""; 9 | public name: string = ""; 10 | public host: string = ""; 11 | public ssl: boolean = false; 12 | public port: number = 80; 13 | public confirmExporting: boolean = false; 14 | public companyId: number = 0; 15 | public userCode: string = ""; 16 | public username: string = ""; 17 | private _password: string = ""; 18 | private decryptedPassword: string = ""; 19 | 20 | get password(): string { 21 | if (!this.decryptedPassword) { 22 | this.decryptedPassword = CryptoService.decrypt(this._password); 23 | } 24 | 25 | return this.decryptedPassword; 26 | } 27 | 28 | set password(password: string) { 29 | this._password = CryptoService.encrypt(password); 30 | } 31 | 32 | constructor(server?: ServerDTO) { 33 | this.id = server?.id || ""; 34 | this.name = server?.name || ""; 35 | this.host = server?.host || ""; 36 | this.ssl = server?.ssl || false; 37 | this.port = server?.port || 0; 38 | this.username = server?.username || ""; 39 | this._password = server?.password || ""; 40 | this.userCode = server?.userCode || ""; 41 | this.confirmExporting = server?.confirmExporting || false; 42 | this.companyId = server?.companyId || 0; 43 | } 44 | 45 | toJSON() { 46 | return { 47 | id: this.id, 48 | name: this.name, 49 | host: this.host, 50 | ssl: this.ssl, 51 | port: this.port, 52 | username: this.username, 53 | password: this._password, 54 | userCode: this.userCode, 55 | confirmExporting: this.confirmExporting, 56 | companyId: this.companyId, 57 | }; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /resources/views/server/server.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | const vscode = acquireVsCodeApi(); 3 | 4 | $(function () { 5 | $("#formServer").on("submit", saveServer); 6 | $("#host").on("change", validateHost); 7 | }); 8 | 9 | /** 10 | * Salva o servidor após efetuar uma conexão bem sucedida 11 | * 12 | * @param {JQuery.Event} event 13 | */ 14 | function saveServer(event) { 15 | event.preventDefault(); 16 | 17 | $("#btnSalvar").addClass("loading").attr("disabled", true); 18 | 19 | vscode.postMessage({ 20 | id: document.getElementById("id").value, 21 | name: document.getElementById("name").value, 22 | host: document.getElementById("host").value, 23 | ssl: document.getElementById("ssl").value == "yes", 24 | port: document.getElementById("port").value, 25 | username: document.getElementById("username").value, 26 | password: document.getElementById("password").value, 27 | confirmExporting: document.getElementById("confirm_pass_exporting").value == "yes", 28 | }); 29 | } 30 | 31 | function validateHost() { 32 | try { 33 | const url = new URL(this.value); 34 | const isSSL = url.protocol.indexOf("https") >= 0; 35 | 36 | let port = url.port; 37 | 38 | if (!port) { 39 | port = isSSL ? 443 : 80; 40 | } 41 | 42 | const name = document.getElementById("name"); 43 | 44 | if (!name.value) { 45 | name.value = url.hostname; 46 | } 47 | 48 | document.getElementById("host").value = url.hostname; 49 | document.getElementById("ssl").value = isSSL ? "yes" : "no"; 50 | document.getElementById("port").value = port; 51 | } catch (error) { 52 | 53 | } 54 | } 55 | 56 | window.addEventListener('message', event => { 57 | $("#btnSalvar").removeClass("loading").attr("disabled", false); 58 | }); 59 | }()); 60 | -------------------------------------------------------------------------------- /templates/globalEvents/validateUpload.txt: -------------------------------------------------------------------------------- 1 | function validateUpload() { 2 | // Exemplo de implementação 3 | 4 | // CompanyId da empresa 5 | var companyId = getValue("WKCompany"); 6 | 7 | // Nome do arquivo com extensão 8 | var fileName = getValue("WKFileName"); 9 | 10 | // Tamanho do arquivo em bytes 11 | var fileSize = getValue("WKFileSize"); 12 | 13 | // Caminho absoluto do arquivo 14 | var filePath = getValue("WKFilePath"); 15 | 16 | // MimeType dos bytes do arquivo, ou seja, independente da extensão 17 | var fileMimeType = getValue("WKFileMimeType"); 18 | 19 | // UserId do usuário que estrealizando o upload 20 | var userId = getValue("WKUser"); 21 | 22 | // A maioria dos mimetypes executáveis começam com "application/x-" 23 | if (fileMimeType.indexOf("application/x-") !== -1) { 24 | 25 | // Porém alguns tipos comçam também como por exemplo: .rar ou .7zip. Então neste caso pode ser feito assim: 26 | if (fileMimeType.indexOf("application/x-rar-compressed") !== -1 || fileMimeType.indexOf("application/x-7z-compressed") !== -1) { 27 | return; 28 | } 29 | 30 | throwsIfBlocked(); 31 | } 32 | 33 | // Podemos bloquear qualquer outro mimetype, por exemplo: 34 | if (fileMimeType.indexOf("application/octet-stream") !== -1 || fileMimeType.indexOf("application/exe") !== -1) { 35 | throwsIfBlocked(); 36 | } 37 | 38 | // Podemos bloquear também pela extensão do arquivo 39 | if (fileName.match(/.*\.(sh|exe|msi|bat|app)/i)) { 40 | throwsIfBlocked(); 41 | } 42 | 43 | // Função usada para logar uma mensagem no log do servidor e retornar o erro na tela 44 | function throwsIfBlocked() { 45 | log.warn("Usuário '" + userId + "' da Empresa: '" + companyId + "' tentou realizar o upload " 46 | + "do Arquivo '" + fileName + "' com o Mimetype: '" + fileMimeType + "' e foi impedido!"); 47 | 48 | throw "Este formato de documento não está de acordo com as políticas de segurança e portanto não será permitida sua publicação na plataforma."; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /resources/views/dataset/dataset.css: -------------------------------------------------------------------------------- 1 | #tabConstraints { 2 | padding: 10px 0; 3 | } 4 | 5 | .tab-content { 6 | margin-bottom: 15px; 7 | } 8 | 9 | #tabConstraints .table thead th { 10 | border-top: none; 11 | } 12 | 13 | #addConstraint { 14 | margin-right: 10px; 15 | } 16 | 17 | #tbResultDataset th, 18 | #tbResultDataset td { 19 | white-space: nowrap; 20 | } 21 | 22 | .selecionarCampos { 23 | display: grid; 24 | grid-template-columns: 1fr 1fr; 25 | grid-auto-rows: minmax(200px, auto); 26 | column-gap: 20px; 27 | } 28 | 29 | .list-sortable { 30 | list-style: none; 31 | padding-left: 0; 32 | border: 1px solid var(--vscode-input-border, var(--gray)); 33 | max-height: 400px; 34 | overflow: scroll; 35 | } 36 | 37 | .list-sortable:first-child { 38 | border-left: none; 39 | } 40 | 41 | .list-sortable:last-child { 42 | border-right: none; 43 | } 44 | 45 | .list-sortable li { 46 | padding: .5rem; 47 | margin-bottom: .5rem; 48 | color: var(--vscode-button-foreground); 49 | background-color: var(--vscode-button-background); 50 | border-color: var(--vscode-button-separator); 51 | } 52 | 53 | .sortable-hover { 54 | cursor: move; 55 | color: #fff; 56 | background-color: var(--vscode-button-hoverBackground, var(--primary)); 57 | border-color: var(--vscode-button-separator); 58 | } 59 | 60 | #tabOrders .form-switch { 61 | padding-left: 1.5rem; 62 | } 63 | 64 | #tabOrders .form-switch .form-check-input, 65 | #tabOrders .form-switch .form-check-label { 66 | cursor: pointer; 67 | } 68 | 69 | #tabOrders .form-switch .form-check-input { 70 | width: 1em; 71 | height: 1.5em; 72 | margin-top: 0; 73 | background-position: top center; 74 | margin-left: -1.5rem; 75 | } 76 | 77 | #tabOrders .form-switch .form-check-input:focus { 78 | border: 1px solid rgba(0,0,0,.25); 79 | box-shadow: none; 80 | outline: none; 81 | background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e"); 82 | } 83 | 84 | #tabOrders .form-switch .form-check-input:checked { 85 | background-color: #FFF; 86 | border: 1px solid rgba(0,0,0,.25); 87 | background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e"); 88 | background-position: bottom center; 89 | } 90 | -------------------------------------------------------------------------------- /src/services/LoginService.ts: -------------------------------------------------------------------------------- 1 | import { ServerDTO } from '../models/ServerDTO'; 2 | import { UtilsService } from './UtilsService'; 3 | 4 | export class LoginService { 5 | 6 | private static cachedCookies : {[key: string]: string} = {}; 7 | 8 | public static async loginAndGetCookies(server: ServerDTO) : Promise { 9 | const cookiesKey = server.host + server.port + server.username; 10 | let cookies = this.cachedCookies[cookiesKey]; 11 | 12 | if (cookies) { 13 | if (await this.isValidCookies(cookies, server)) { 14 | return cookies; 15 | } 16 | 17 | delete this.cachedCookies[cookiesKey]; 18 | } 19 | 20 | cookies = await this.tryAuthenticate(server); 21 | 22 | if (this.isAuthenticated(cookies) && !await this.isValidCookies(cookies, server)) { 23 | await this.setDemoMode(server); 24 | 25 | cookies = await this.tryAuthenticate(server); 26 | } 27 | 28 | this.cachedCookies[cookiesKey] = cookies; 29 | 30 | return cookies; 31 | } 32 | 33 | private static isAuthenticated(cookies: string) { 34 | return cookies.includes("JSESSIONIDSSO") || cookies.includes("jwt.token"); 35 | } 36 | 37 | private static async tryAuthenticate(server: ServerDTO) { 38 | const loginUrl = `${UtilsService.getHost(server)}/portal/api/servlet/login.do`; 39 | const loginData = `j_username=${server.username}&j_password=${server.password}`; 40 | 41 | const response = await fetch(loginUrl, { 42 | method: 'POST', 43 | headers: { 44 | 'Content-Type': 'application/x-www-form-urlencoded', 45 | }, 46 | body: loginData 47 | }); 48 | 49 | return (response.headers.get('set-cookie') || '') 50 | .split(',') 51 | .map(cookie => cookie.split(';')[0]) 52 | .join('; '); 53 | } 54 | 55 | private static async isValidCookies(cookiesCached: string, server: ServerDTO) : Promise { 56 | const pingUrl = `${UtilsService.getHost(server)}/portal/p/api/servlet/ping`; 57 | 58 | const response = await fetch(pingUrl, { 59 | method: 'POST', 60 | headers: { 61 | 'Cookie': cookiesCached 62 | } 63 | }); 64 | 65 | if (response.ok) { 66 | const body = await response.text(); 67 | if (body.startsWith("{") && body.includes("pong")) { 68 | return true; 69 | } 70 | } 71 | 72 | return false; 73 | } 74 | 75 | private static async setDemoMode(server: ServerDTO) { 76 | const pingUrl = `${UtilsService.getHost(server)}/portal/api/servlet/license.do?demo=true`; 77 | 78 | await fetch(pingUrl, { 79 | method: 'POST' 80 | }); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/models/DocumentDTO.ts: -------------------------------------------------------------------------------- 1 | export interface DocumentDTO { 2 | accessCount: number; 3 | activeUserApprover: boolean; 4 | activeVersion: boolean; 5 | additionalComments: string; 6 | allowMuiltiCardsPerUser: boolean; 7 | approvalAndOr: boolean; 8 | approved: boolean; 9 | approvedDate: string; 10 | articleContent: string; 11 | atualizationId: number; 12 | backgroundColor: string; 13 | backgroundImage: string; 14 | bannerImage: string; 15 | cardDescription: string; 16 | colleagueId: string; 17 | colleagueName: string; 18 | companyId: number; 19 | convertDocumentType: number; 20 | crc: number; 21 | createDate: string; 22 | createDateInMilliseconds: number; 23 | datasetName: string; 24 | dateFormStarted: boolean; 25 | deleted: boolean; 26 | documentDescription: string; 27 | documentId: number; 28 | documentKeyWord: string; 29 | documentPropertyNumber: number; 30 | documentPropertyVersion: number; 31 | documentType: string; 32 | documentTypeId: string; 33 | downloadEnabled: boolean; 34 | draft: boolean; 35 | expirationDate: string; 36 | expiredForm: boolean; 37 | expires: boolean; 38 | externalDocumentId: string; 39 | favorite: boolean; 40 | fileURL: string; 41 | folderId: number; 42 | forAproval: boolean; 43 | hashAnnotations: string; 44 | iconId: number; 45 | iconPath: string; 46 | imutable: boolean; 47 | indexed: boolean; 48 | inheritApprovers: boolean; 49 | inheritSecurity: boolean; 50 | internalVisualizer: boolean; 51 | isEncrypted: boolean; 52 | keyWord: string; 53 | languageId: string; 54 | languageIndicator: string; 55 | lastModifiedDate: string; 56 | lastModifiedTime: string; 57 | metaListId: number; 58 | metaListRecordId: number; 59 | newStructure: boolean; 60 | notificationDays: number; 61 | onCheckout: boolean; 62 | parentDocumentId: number; 63 | pdfRenderEngine: string; 64 | permissionType: number; 65 | phisicalFile: string; 66 | phisicalFileSize: number; 67 | priority: number; 68 | privateColleagueId: string; 69 | privateDocument: boolean; 70 | protectedCopy: boolean; 71 | publicDocument: boolean; 72 | publisherId: string; 73 | publisherName: string; 74 | quota: number; 75 | relatedFiles: string; 76 | restrictionType: number; 77 | rowId: number; 78 | searchNumber: number; 79 | securityLevel: number; 80 | siteCode: string; 81 | socialDocument: string; 82 | tool: boolean; 83 | topicId: number; 84 | translated: boolean; 85 | UUID: string; 86 | updateIsoProperties: boolean; 87 | userAnswerForm: boolean; 88 | userNotify: boolean; 89 | userPermission: number; 90 | validationStartDate: string; 91 | version: number; 92 | versionDescription: string; 93 | versionOption: string; 94 | visualization: string; 95 | volumeId: string; 96 | watermarkId: number; 97 | } 98 | -------------------------------------------------------------------------------- /src/extensions/GlobalEventExtension.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import {GlobalEventService} from "../services/GlobalEventService"; 3 | import {TemplateService} from "../services/TemplateService"; 4 | import {UtilsService} from "../services/UtilsService"; 5 | import {readFileSync} from "fs"; 6 | 7 | export class GlobalEventExtension { 8 | 9 | public static activate(context: vscode.ExtensionContext): void { 10 | context.subscriptions.push(vscode.commands.registerCommand( 11 | "fluiggers-fluig-vscode-extension.newGlobalEvent", 12 | GlobalEventExtension.createGlobalEvent 13 | )); 14 | context.subscriptions.push(vscode.commands.registerCommand( 15 | "fluiggers-fluig-vscode-extension.exportGlobalEvent", 16 | GlobalEventExtension.exportGlobalEvent 17 | )); 18 | context.subscriptions.push(vscode.commands.registerCommand( 19 | "fluiggers-fluig-vscode-extension.importManyGlobalEvent", 20 | GlobalEventService.importMany 21 | )); 22 | context.subscriptions.push(vscode.commands.registerCommand( 23 | "fluiggers-fluig-vscode-extension.importGlobalEvent", 24 | GlobalEventService.import 25 | )); 26 | context.subscriptions.push(vscode.commands.registerCommand( 27 | "fluiggers-fluig-vscode-extension.deleteGlobalEvent", 28 | GlobalEventService.delete 29 | )); 30 | } 31 | 32 | /** 33 | * Cria um Evento Global 34 | */ 35 | private static async createGlobalEvent() { 36 | const eventName: string = await vscode.window.showQuickPick( 37 | TemplateService.globalEventsNames, 38 | { 39 | canPickMany: false, 40 | placeHolder: "Selecione o Evento" 41 | } 42 | ) || ""; 43 | 44 | if (!eventName) { 45 | return; 46 | } 47 | 48 | const eventFilename = eventName + ".js"; 49 | const eventUri = vscode.Uri.joinPath( 50 | UtilsService.getWorkspaceUri(), 51 | "events", 52 | eventFilename 53 | ); 54 | 55 | try { 56 | // Se Evento já existe carrega o arquivo no editor 57 | await vscode.workspace.fs.stat(eventUri); 58 | return vscode.window.showTextDocument(eventUri); 59 | } catch (err) { 60 | 61 | } 62 | 63 | await vscode.workspace.fs.writeFile( 64 | eventUri, 65 | readFileSync(vscode.Uri.joinPath(TemplateService.globalEventsUri, `${eventName}.txt`).fsPath) 66 | ); 67 | vscode.window.showTextDocument(eventUri); 68 | } 69 | 70 | private static exportGlobalEvent(fileUri: vscode.Uri) { 71 | // Ativado pela Tecla de Atalho 72 | if (!fileUri) { 73 | if (!vscode.window.activeTextEditor) { 74 | vscode.window.showErrorMessage("Não há editor de texto ativo com Evento Global"); 75 | return; 76 | } 77 | fileUri = vscode.window.activeTextEditor.document.uri; 78 | } 79 | 80 | GlobalEventService.export(fileUri); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/services/UtilsService.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { ServerDTO } from '../models/ServerDTO'; 3 | import { LoginService } from './LoginService'; 4 | 5 | export class UtilsService { 6 | public static generateRandomID() { 7 | return Math.random().toString(36).substring(2, 15) + Date.now().toString(36) + Math.random().toString(36).substring(2, 15); 8 | } 9 | 10 | /** 11 | * Retorna o PATH do workspace 12 | */ 13 | public static getWorkspaceUri(): vscode.Uri { 14 | if (!vscode.workspace.workspaceFolders) { 15 | throw new Error("É necessário estar em Workspace / Diretório."); 16 | } 17 | return vscode.workspace.workspaceFolders[0].uri; 18 | } 19 | 20 | public static getHost(server: ServerDTO): string { 21 | const schema: string = server.ssl ? "https" : "http"; 22 | const port: string = [80, 443].includes(server.port) ? "" : `:${server.port}`; 23 | 24 | return `${schema}://${server.host}${port}`; 25 | } 26 | 27 | /** 28 | * Pega a URL para um serviço REST já com usuário e senha do servidor 29 | * 30 | * @param server Servidor selecionado 31 | * @param basePath Caminho base do recurso REST (ex: /ecm/api/rest/ecm/dataset/) 32 | * @param resource Recurso solicitado (ex: loadDataset) 33 | * @param params Objeto com parâmetros adicionais para inserir na Url 34 | */ 35 | public static getRestUrl(server: ServerDTO, basePath: string, resource: string, params?: {[s: string]: string}): URL { 36 | const url = new URL(`${UtilsService.getHost(server)}${basePath}${resource}`); 37 | 38 | if (!params) { 39 | return url; 40 | } 41 | 42 | for (const [key, value] of Object.entries(params)) { 43 | url.searchParams.append(key, value); 44 | } 45 | 46 | return url; 47 | } 48 | 49 | /** 50 | * Confirma a senha do servidor para exportar artefatos 51 | */ 52 | public static async confirmPassword(server: ServerDTO): Promise { 53 | let isPasswordCorrect: boolean = true; 54 | 55 | do { 56 | const confirmPassword = await vscode.window.showInputBox({ 57 | prompt: "Informe a senha do servidor " + server.name, 58 | password: true 59 | }) || ""; 60 | 61 | if (!confirmPassword) { 62 | return false; 63 | } else if (confirmPassword !== server.password) { 64 | vscode.window.showWarningMessage(`A senha informada para o servidor "${server.name}" está incorreta!`); 65 | isPasswordCorrect = false; 66 | } else { 67 | isPasswordCorrect = true; 68 | } 69 | } while (!isPasswordCorrect); 70 | 71 | return isPasswordCorrect; 72 | } 73 | 74 | public static async validateServerHasFluiggersWidget(server: ServerDTO) { 75 | const url = new URL(`${UtilsService.getHost(server)}/fluiggersWidget/api/ping`); 76 | 77 | const hasWidget = await fetch( 78 | url, 79 | { 80 | method: "GET", 81 | headers: { 'Cookie': await LoginService.loginAndGetCookies(server) }, 82 | } 83 | ) 84 | .then(async function (r) { 85 | if (r.status != 200) { 86 | return false; 87 | } 88 | 89 | return 'pong' === await r.text(); 90 | }); 91 | 92 | if (!hasWidget) { 93 | throw new Error("Você precisa instalar a FluiggersWdiget nesse servidor para executar essa operação.") 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/extensions/DatasetExtension.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import {readFileSync} from "fs"; 3 | import {DatasetService} from "../services/DatasetService"; 4 | import {UtilsService} from "../services/UtilsService"; 5 | import {TemplateService} from "../services/TemplateService"; 6 | import {ServerService} from "../services/ServerService"; 7 | import {DatasetView} from "../views/DatasetView"; 8 | 9 | export class DatasetExtension { 10 | 11 | public static activate(context: vscode.ExtensionContext): void { 12 | context.subscriptions.push(vscode.commands.registerCommand( 13 | "fluiggers-fluig-vscode-extension.newDataset", 14 | DatasetExtension.createDataset 15 | )); 16 | context.subscriptions.push(vscode.commands.registerCommand( 17 | "fluiggers-fluig-vscode-extension.importManyDataset", 18 | DatasetService.importMany 19 | )); 20 | context.subscriptions.push(vscode.commands.registerCommand( 21 | "fluiggers-fluig-vscode-extension.importDataset", 22 | DatasetService.import 23 | )); 24 | context.subscriptions.push(vscode.commands.registerCommand( 25 | "fluiggers-fluig-vscode-extension.exportDataset", 26 | DatasetExtension.exportDataset 27 | )); 28 | context.subscriptions.push(vscode.commands.registerCommand( 29 | "fluiggers-fluig-vscode-extension.searchDataset", 30 | DatasetExtension.searchDataset(context) 31 | )); 32 | context.subscriptions.push(vscode.commands.registerCommand( 33 | "fluiggers-fluig-vscode-extension.exportDatasetFolder", 34 | DatasetExtension.exportDatasetFolder 35 | )); 36 | } 37 | 38 | /** 39 | * Cria um Dataset 40 | */ 41 | private static async createDataset() { 42 | let dataset: string = await vscode.window.showInputBox({ 43 | prompt: "Qual o nome do Dataset (sem espaços e sem caracteres especiais)?", 44 | placeHolder: "ds_nome_dataset" 45 | }) || ""; 46 | 47 | if (!dataset) { 48 | return; 49 | } 50 | 51 | if (!dataset.endsWith(".js")) { 52 | dataset += ".js"; 53 | } 54 | 55 | const datasetUri = vscode.Uri.joinPath(UtilsService.getWorkspaceUri(), "datasets", dataset); 56 | 57 | try { 58 | // Se Dataset já existe carrega o arquivo no editor 59 | await vscode.workspace.fs.stat(datasetUri); 60 | return vscode.window.showTextDocument(datasetUri); 61 | } catch (err) { 62 | 63 | } 64 | 65 | await vscode.workspace.fs.writeFile( 66 | datasetUri, 67 | readFileSync(vscode.Uri.joinPath(TemplateService.templatesUri, 'createDataset.txt').fsPath) 68 | ); 69 | vscode.window.showTextDocument(datasetUri); 70 | } 71 | 72 | private static exportDataset(fileUri: vscode.Uri) { 73 | // Ativado pela Tecla de Atalho 74 | if (!fileUri) { 75 | if (!vscode.window.activeTextEditor) { 76 | vscode.window.showErrorMessage("Não há editor de texto ativo com Dataset"); 77 | return; 78 | } 79 | fileUri = vscode.window.activeTextEditor.document.uri; 80 | } 81 | 82 | DatasetService.export(fileUri); 83 | } 84 | 85 | /** 86 | * Realiza a importação de um dataset específico 87 | */ 88 | private static searchDataset(context: vscode.ExtensionContext) { 89 | return async function() { 90 | const server = await ServerService.getSelect(); 91 | if (!server) { 92 | return; 93 | } 94 | new DatasetView(context, server).show(); 95 | }; 96 | } 97 | 98 | /** 99 | * Exporta todos os datasets de uma pasta selecionada 100 | * 101 | * Se não tiver pasta selecionada entende-se que é pra exportar todos os 102 | * datasets do workspace. 103 | */ 104 | private static exportDatasetFolder(folderUri: vscode.Uri) { 105 | const datasetsUri = folderUri ? folderUri : vscode.Uri.joinPath(UtilsService.getWorkspaceUri(), "datasets"); 106 | DatasetService.exportFromFolder(datasetsUri); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/views/ServerView.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import {ServerDTO} from '../models/ServerDTO'; 3 | import {ServerService} from '../services/ServerService'; 4 | import * as fs from 'fs'; 5 | import {UserService} from '../services/UserService'; 6 | import {Server} from '../models/Server'; 7 | 8 | const compile = require('template-literal'); 9 | 10 | export class ServerView { 11 | 12 | private currentPanel: vscode.WebviewPanel | undefined = undefined; 13 | private serverData: ServerDTO | undefined = undefined; 14 | 15 | constructor(private context: vscode.ExtensionContext) {} 16 | 17 | public setServerData(server: ServerDTO) { 18 | this.serverData = server; 19 | } 20 | 21 | public show() { 22 | this.currentPanel = this.createWebViewPanel(); 23 | this.currentPanel.webview.html = this.getWebViewContent(); 24 | this.currentPanel.onDidDispose( 25 | () => this.currentPanel = undefined, 26 | null 27 | ); 28 | this.currentPanel.webview.onDidReceiveMessage( 29 | obj => this.messageListener(obj), 30 | undefined 31 | ); 32 | } 33 | 34 | private getWebViewContent() { 35 | const htmlPath = vscode.Uri.joinPath(this.context.extensionUri, 'dist', 'views', 'server', 'server.html'); 36 | const runTemplate = compile(fs.readFileSync(htmlPath.with({scheme: 'vscode-resource'}).fsPath)); 37 | 38 | return runTemplate({ 39 | jquery: this.currentPanel?.webview.asWebviewUri(vscode.Uri.joinPath(this.context.extensionUri, 'dist', 'libs', 'jquery.min.js')), 40 | bootstrapCss: this.currentPanel?.webview.asWebviewUri(vscode.Uri.joinPath(this.context.extensionUri, 'dist', 'libs', 'bootstrap.min.css')), 41 | themeCss: this.currentPanel?.webview.asWebviewUri(vscode.Uri.joinPath(this.context.extensionUri, 'dist', 'css', 'theme.css')), 42 | serverJs: this.currentPanel?.webview.asWebviewUri(vscode.Uri.joinPath(this.context.extensionUri, 'dist', 'views', 'server', 'server.js')), 43 | serverData: this.serverData, 44 | ssl: (this.serverData && this.serverData.ssl) ? this.serverData.ssl : false, 45 | confirmExporting: (this.serverData && this.serverData.confirmExporting) ? this.serverData.confirmExporting : false 46 | }); 47 | } 48 | 49 | private createWebViewPanel() { 50 | return vscode.window.createWebviewPanel( 51 | "fluig-vscode-extension.addServer", 52 | this.serverData !== undefined ? "Editar Servidor" : "Adicionar Servidor", 53 | vscode.ViewColumn.One, 54 | { 55 | enableScripts: true, 56 | localResourceRoots: [this.context.extensionUri], 57 | retainContextWhenHidden: true 58 | } 59 | ); 60 | } 61 | 62 | private messageListener(obj: any) { 63 | if (!obj.name || !obj.host || !obj.port || !obj.username || !obj.password) { 64 | return; 65 | } 66 | 67 | if (!this.currentPanel || !this.currentPanel.webview) { 68 | return; 69 | } 70 | 71 | const webview = this.currentPanel.webview; 72 | 73 | const server: ServerDTO = new Server(); 74 | server.id = obj.id; 75 | server.name = obj.name; 76 | server.host = obj.host; 77 | server.ssl = obj.ssl; 78 | server.port = parseInt(obj.port); 79 | server.userCode = ""; 80 | server.username = obj.username; 81 | server.password = obj.password; 82 | server.confirmExporting = obj.confirmExporting; 83 | server.companyId = 0; 84 | 85 | UserService.getUser(server).then((response:any) => { 86 | if (!response.content) { 87 | throw response.message?.message; 88 | } 89 | 90 | server.companyId = response.content.tenantId; 91 | server.userCode = response.content.userCode; 92 | ServerService.createOrUpdate(server); 93 | 94 | if (this.currentPanel) { 95 | this.currentPanel.dispose(); 96 | } 97 | }).catch((e) => { 98 | webview.postMessage({ 99 | command: 'error', 100 | message: e.message || e 101 | }); 102 | 103 | vscode.window.showErrorMessage(`Falha na conexão com o servidor ${server.name}.\nErro retornado: ${e.message || e}`); 104 | }); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /resources/views/server/server.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Adicionar servidor 8 | 9 | 10 | 19 | 20 | 21 |
22 |

${d.serverData ? 'Editar Servidor' : 'Adicionar Servidor'}

23 | 24 |
25 |
26 |
27 | 28 | 29 | 30 |
31 | 32 |
33 | 34 | 43 |
44 | 45 |
46 | 47 | 51 |
52 | 53 |
54 | 55 | 66 |
67 | 68 |
69 | 70 | 78 |
79 | 80 |
81 | 82 | 90 |
91 | 92 |
93 | 94 | 98 |
99 |
100 | 101 |

102 | 106 |

107 |
108 |
109 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /src/providers/ServerItemProvider.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { ServerDTO } from '../models/ServerDTO'; 3 | import { ServerService } from '../services/ServerService'; 4 | import * as fs from 'fs'; 5 | import { ServerView } from '../views/ServerView'; 6 | import { Server } from '../models/Server'; 7 | import { DatasetView } from '../views/DatasetView'; 8 | 9 | 10 | export class ServerItem extends vscode.TreeItem { 11 | constructor( 12 | public context: vscode.ExtensionContext, 13 | public readonly label: string, 14 | public readonly collapsibleState: vscode.TreeItemCollapsibleState, 15 | public server: ServerDTO 16 | ) { 17 | super(label, collapsibleState); 18 | } 19 | 20 | iconPath = { 21 | light: vscode.Uri.joinPath(this.context.extensionUri, 'dist', 'images', 'light', 'server-environment.svg'), 22 | dark: vscode.Uri.joinPath(this.context.extensionUri, 'dist', 'images', 'dark', 'server-environment.svg') 23 | }; 24 | 25 | contextValue = 'serverItem'; 26 | } 27 | 28 | export class DatasetItem extends ServerItem { 29 | constructor( 30 | public context: vscode.ExtensionContext, 31 | public readonly label: string, 32 | public readonly collapsibleState: vscode.TreeItemCollapsibleState, 33 | public server: ServerDTO 34 | ) { 35 | super(context, label, collapsibleState, server); 36 | } 37 | 38 | iconPath = { 39 | light: vscode.Uri.joinPath(this.context.extensionUri, 'dist', 'images', 'light', 'database.svg'), 40 | dark: vscode.Uri.joinPath(this.context.extensionUri, 'dist', 'images', 'dark', 'database.svg') 41 | }; 42 | 43 | contextValue = 'DatasetItem'; 44 | } 45 | 46 | export class ServerItemProvider implements vscode.TreeDataProvider { 47 | 48 | private _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter(); 49 | readonly onDidChangeTreeData: vscode.Event = this._onDidChangeTreeData.event; 50 | 51 | public serverItems: Array = []; 52 | 53 | constructor(public context: vscode.ExtensionContext) { 54 | this.serverConfigListener(); 55 | } 56 | 57 | public getTreeItem(element: ServerItem): vscode.TreeItem { 58 | return element; 59 | } 60 | 61 | public getChildren(element?: ServerItem): vscode.ProviderResult { 62 | if (element) { 63 | return Promise.resolve([ 64 | new DatasetItem(this.context, "Dataset", vscode.TreeItemCollapsibleState.None, element.server), 65 | ]); 66 | } else { 67 | return Promise.resolve(this.serverItems); 68 | } 69 | } 70 | 71 | public refresh(): void { 72 | this._onDidChangeTreeData.fire(); 73 | } 74 | 75 | public add(): void { 76 | const serverView = new ServerView(this.context); 77 | serverView.show(); 78 | } 79 | 80 | public delete(serverItem: ServerItem): void { 81 | vscode.window.showInformationMessage(`Deseja excluir o servidor ${serverItem.server.name}?`, "Sim", "Não") 82 | .then(selection => { 83 | if (selection === "Sim") { 84 | const index = this.serverItems.indexOf(serverItem); 85 | 86 | if (index < 0 || serverItem?.server?.id === undefined) { 87 | return; 88 | } 89 | 90 | ServerService.delete(serverItem.server.id); 91 | } 92 | }); 93 | } 94 | 95 | public update(serverItem: ServerItem): void { 96 | const serverView = new ServerView(this.context); 97 | serverView.setServerData(new Server(serverItem.server)); 98 | serverView.show(); 99 | } 100 | 101 | public datasetView(datasetItem: DatasetItem): void { 102 | new DatasetView(this.context, new Server(datasetItem.server)).show(); 103 | } 104 | 105 | private getServers(): ServerItem[] { 106 | const serverConfig = ServerService.getServerConfig(); 107 | const listServer = new Array(); 108 | 109 | serverConfig.configurations.forEach((element: ServerDTO) => { 110 | const serverItem = new ServerItem( 111 | this.context, 112 | element.name, 113 | vscode.TreeItemCollapsibleState.Collapsed, 114 | element 115 | ); 116 | 117 | listServer.push(serverItem); 118 | }); 119 | 120 | return listServer.sort((srv1, srv2) => { 121 | const label1 = srv1.label.toLowerCase(); 122 | const label2 = srv2.label.toLowerCase(); 123 | if (label1 > label2) { return 1; } 124 | if (label1 < label2) { return -1; } 125 | return 0; 126 | }); 127 | } 128 | 129 | private serverConfigListener(): void { 130 | const fileServer = ServerService.getFileServerConfig(); 131 | 132 | this.serverItems = this.getServers(); 133 | fs.watch(fileServer, { encoding: 'buffer' }, (eventType, filename) => { 134 | if (filename && eventType === 'change') { 135 | this.serverItems = this.getServers(); 136 | this.refresh(); 137 | } 138 | }); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/extensions/FormExtension.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import {FormService} from "../services/FormService"; 3 | import {UtilsService} from "../services/UtilsService"; 4 | import {readFileSync} from "fs"; 5 | import {TemplateService} from "../services/TemplateService"; 6 | 7 | export class FormExtension { 8 | 9 | public static activate(context: vscode.ExtensionContext): void { 10 | context.subscriptions.push(vscode.commands.registerCommand( 11 | "fluiggers-fluig-vscode-extension.newForm", 12 | FormExtension.createForm 13 | )); 14 | context.subscriptions.push(vscode.commands.registerCommand( 15 | "fluiggers-fluig-vscode-extension.newFormEvent", 16 | FormExtension.createFormEvent 17 | )); 18 | context.subscriptions.push(vscode.commands.registerCommand( 19 | "fluiggers-fluig-vscode-extension.importManyForm", 20 | FormService.importMany 21 | )); 22 | context.subscriptions.push(vscode.commands.registerCommand( 23 | "fluiggers-fluig-vscode-extension.importForm", 24 | FormService.import 25 | )); 26 | context.subscriptions.push(vscode.commands.registerCommand( 27 | "fluiggers-fluig-vscode-extension.exportForm", 28 | function (fileUri: vscode.Uri) { 29 | // Ativado pela Tecla Atalho 30 | if (!fileUri) { 31 | if (!vscode.window.activeTextEditor) { 32 | vscode.window.showErrorMessage("Não há editor de texto ativo com Formulário"); 33 | return; 34 | } 35 | fileUri = vscode.window.activeTextEditor.document.uri; 36 | } 37 | 38 | FormService.export(context, fileUri); 39 | } 40 | )); 41 | } 42 | 43 | 44 | /** 45 | * Cria um Formulário 46 | */ 47 | private static async createForm() { 48 | let formName: string = await vscode.window.showInputBox({ 49 | prompt: "Qual o nome do Formulário (sem espaços e sem caracteres especiais)?", 50 | placeHolder: "NomeFormulario" 51 | }) || ""; 52 | 53 | if (!formName) { 54 | return; 55 | } 56 | 57 | const formFileName = formName + ".html"; 58 | const formUri = vscode.Uri.joinPath( 59 | UtilsService.getWorkspaceUri(), 60 | "forms", 61 | formName, 62 | formFileName 63 | ); 64 | 65 | try { 66 | // Se Formulário já existe carrega o arquivo no editor 67 | await vscode.workspace.fs.stat(formUri); 68 | return vscode.window.showTextDocument(formUri); 69 | } catch (err) { 70 | 71 | } 72 | 73 | await vscode.workspace.fs.writeFile( 74 | formUri, 75 | readFileSync(vscode.Uri.joinPath(TemplateService.templatesUri, 'form.txt').fsPath) 76 | ); 77 | vscode.window.showTextDocument(formUri); 78 | } 79 | 80 | /** 81 | * Cria um Evento de Formulário 82 | */ 83 | private static async createFormEvent(folderUri: vscode.Uri) { 84 | // Ativado pela Tecla de Atalho 85 | if (!folderUri) { 86 | if (!vscode.window.activeTextEditor) { 87 | vscode.window.showErrorMessage("Não há editor de texto ativo com Dataset"); 88 | return; 89 | } 90 | folderUri = vscode.window.activeTextEditor.document.uri; 91 | } 92 | 93 | if (!folderUri.path.includes("/forms/")) { 94 | vscode.window.showErrorMessage("Necessário selecionar um formulário para criar o evento."); 95 | return; 96 | } 97 | 98 | const formName: string = folderUri.path.replace(/.*\/forms\/([^/]+).*/, "$1"); 99 | 100 | const newFunctionOption = 'Nova Função'; 101 | 102 | let eventName: string = await vscode.window.showQuickPick( 103 | TemplateService.formEventsNames.concat(newFunctionOption), 104 | { 105 | canPickMany: false, 106 | placeHolder: "Selecione o Evento" 107 | } 108 | ) || ""; 109 | 110 | if (!eventName) { 111 | return; 112 | } 113 | 114 | let isNewFunction = false; 115 | 116 | if (eventName === newFunctionOption) { 117 | eventName = await vscode.window.showInputBox({ 118 | prompt: "Qual o nome da Nova Função (sem espaços e sem caracteres especiais)?", 119 | placeHolder: "nomeFuncao" 120 | }) || ""; 121 | 122 | if (!eventName) { 123 | return; 124 | } 125 | 126 | isNewFunction = true; 127 | } 128 | 129 | const eventFilename = eventName + ".js"; 130 | const eventUri = vscode.Uri.joinPath( 131 | UtilsService.getWorkspaceUri(), 132 | "forms", 133 | formName, 134 | 'events', 135 | eventFilename 136 | ); 137 | 138 | try { 139 | // Se Evento já existe carrega o arquivo no editor 140 | await vscode.workspace.fs.stat(eventUri); 141 | return vscode.window.showTextDocument(eventUri); 142 | } catch (err) { 143 | 144 | } 145 | 146 | await vscode.workspace.fs.writeFile( 147 | eventUri, 148 | isNewFunction 149 | ? Buffer.from(TemplateService.createEmptyFunction(eventName), "utf-8") 150 | : readFileSync(vscode.Uri.joinPath(TemplateService.formEventsUri, `${eventName}.txt`).fsPath) 151 | ); 152 | 153 | vscode.window.showTextDocument(eventUri); 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | const { src, dest, series, parallel } = require('gulp'); 2 | const concat = require('gulp-concat'); 3 | const uglify = require('gulp-uglify'); 4 | const cleanCSS = require('gulp-clean-css'); 5 | const footer = require('gulp-footer'); 6 | const fs = require('fs'); 7 | 8 | const destFolder = 'dist'; 9 | 10 | const imagesExtensions = [".jpg", ".jpeg", ".png", ".svg"]; 11 | 12 | const gulpSrcOptions = { 13 | encoding: file => imagesExtensions.includes(file.extname) ? false : "utf8" 14 | } 15 | 16 | function clean(cb) { 17 | try { 18 | fs.rmSync(destFolder, { recursive: true }); 19 | } catch (err) { 20 | 21 | } 22 | cb(); 23 | } 24 | 25 | function buildJquery(cb) { 26 | src('node_modules/jquery/dist/jquery.min.js') 27 | .pipe(dest(`${destFolder}/libs`)); 28 | 29 | cb(); 30 | } 31 | 32 | function buildBootstrapCss(cb) { 33 | src('node_modules/bootstrap/dist/css/bootstrap.min.css') 34 | .pipe(dest(`${destFolder}/libs`)); 35 | 36 | cb(); 37 | } 38 | 39 | function buildBootstrapJs(cb) { 40 | src('node_modules/bootstrap/dist/js/bootstrap.min.js') 41 | .pipe(dest(`${destFolder}/libs`)); 42 | 43 | cb(); 44 | } 45 | 46 | function buildSelect2Css(cb) { 47 | src([ 48 | 'node_modules/select2/dist/css/select2.min.css', 49 | 'node_modules/select2-bootstrap-5-theme/dist/select2-bootstrap-5-theme.min.css', 50 | ]) 51 | .pipe(concat('select2.min.css')) 52 | .pipe(dest(`${destFolder}/libs`)); 53 | 54 | cb(); 55 | } 56 | 57 | function buildSelect2Js(cb) { 58 | src([ 59 | 'node_modules/select2/dist/js/select2.full.min.js', 60 | 'node_modules/select2/dist/js/i18n/pt-BR.js', 61 | ]) 62 | .pipe(concat('select2.min.js')) 63 | .pipe(footer(`\n$.fn.select2.defaults.set("language", "pt-BR");\n`)) 64 | .pipe(footer(`\n$(document).on('select2:open', () => document.querySelector('.select2-search__field').focus());\n`)) // Corrige bug JQuery + Select2 no foco 65 | .pipe(dest(`${destFolder}/libs`)); 66 | 67 | cb(); 68 | } 69 | 70 | function buildDatatablesCss(cb) { 71 | src([ 72 | 'node_modules/datatables.net-bs5/css/dataTables.bootstrap5.min.css', 73 | 'node_modules/datatables.net-buttons-bs5/css/buttons.bootstrap5.min.css', 74 | 'node_modules/datatables.net-fixedheader-bs5/css/fixedHeader.bootstrap5.min.css', 75 | 'node_modules/datatables.net-scroller-bs5/css/scroller.bootstrap5.min.css', 76 | ]) 77 | .pipe(concat('datatables.min.css')) 78 | .pipe(dest(`${destFolder}/libs`)); 79 | 80 | cb(); 81 | } 82 | 83 | function buildDatatablesJs(cb) { 84 | let ptBrJson = JSON.stringify(JSON.parse(fs.readFileSync('node_modules/datatables.net-plugins/i18n/pt-BR.json').toString())); 85 | 86 | src([ 87 | 'node_modules/jszip/dist/jszip.min.js', 88 | 'node_modules/datatables.net/js/dataTables.min.js', 89 | 'node_modules/datatables.net-bs5/js/dataTables.bootstrap5.min.js', 90 | 'node_modules/datatables.net-buttons/js/dataTables.buttons.min.js', 91 | 'node_modules/datatables.net-buttons/js/buttons.html5.min.js', 92 | 'node_modules/datatables.net-buttons-bs5/js/buttons.bootstrap5.min.js', 93 | 'node_modules/datatables.net-fixedheader/js/dataTables.fixedHeader.min.js', 94 | 'node_modules/datatables.net-fixedheader-bs5/js/fixedHeader.bootstrap5.min.js', 95 | 'node_modules/datatables.net-scroller/js/dataTables.scroller.min.js', 96 | 'node_modules/datatables.net-scroller-bs5/js/scroller.bootstrap5.min.js', 97 | ]) 98 | .pipe(concat('datatables.min.js')) 99 | .pipe(footer(`\n$.extend($.fn.dataTable.defaults, {language: ${ptBrJson}});\n`)) 100 | .pipe(dest(`${destFolder}/libs`)); 101 | 102 | cb(); 103 | } 104 | 105 | function buildHtml5Sortable(cb) { 106 | src('node_modules/html5sortable/dist/html5sortable.min.js') 107 | .pipe(dest(`${destFolder}/libs`)); 108 | 109 | cb(); 110 | } 111 | 112 | function buildResourcesCss(cb) { 113 | src('resources/**/*.css') 114 | .pipe(cleanCSS()) 115 | .pipe(dest(destFolder)); 116 | 117 | cb(); 118 | } 119 | 120 | function buildResourcesJs(cb) { 121 | src('resources/**/*.js') 122 | .pipe(uglify()) 123 | .pipe(dest(destFolder)); 124 | 125 | cb(); 126 | } 127 | 128 | function buildResourcesHtml(cb) { 129 | src('resources/**/*.html') 130 | .pipe(dest(destFolder)); 131 | 132 | cb(); 133 | } 134 | 135 | function buildResourcesImages(cb) { 136 | src( 137 | 'resources/images/**/*.{jpg,jpeg,png,svg}', 138 | { 139 | encoding: false 140 | } 141 | ) 142 | .pipe(dest('dist/images')); 143 | 144 | cb(); 145 | } 146 | 147 | function buildTemplates(cb) { 148 | src('templates/**', gulpSrcOptions) 149 | .pipe(dest('dist/templates')); 150 | 151 | cb(); 152 | } 153 | 154 | exports.default = series( 155 | clean, 156 | parallel( 157 | buildJquery, 158 | buildBootstrapCss, 159 | buildBootstrapJs, 160 | buildSelect2Css, 161 | buildSelect2Js, 162 | buildHtml5Sortable, 163 | buildDatatablesCss, 164 | buildDatatablesJs, 165 | buildResourcesJs, 166 | buildResourcesCss, 167 | buildResourcesImages, 168 | buildResourcesHtml, 169 | buildTemplates 170 | ) 171 | ); 172 | 173 | exports.clean = clean; 174 | 175 | exports.buildLibraries = parallel([ 176 | buildJquery, 177 | buildBootstrapCss, 178 | buildBootstrapJs, 179 | buildSelect2Css, 180 | buildSelect2Js, 181 | buildHtml5Sortable, 182 | buildDatatablesCss, 183 | buildDatatablesJs, 184 | ]); 185 | 186 | exports.buildResources = parallel([ 187 | buildResourcesJs, 188 | buildResourcesCss, 189 | buildResourcesImages, 190 | buildResourcesHtml, 191 | ]); 192 | 193 | exports.buildTemplates = buildTemplates; 194 | -------------------------------------------------------------------------------- /src/services/WorkflowService.ts: -------------------------------------------------------------------------------- 1 | import { Uri, window } from 'vscode'; 2 | import { readFileSync } from "fs"; 3 | import { glob } from "glob"; 4 | import { UtilsService } from "./UtilsService"; 5 | import { ServerService } from "./ServerService"; 6 | import {LoginService} from "./LoginService"; 7 | import { ServerDTO } from '../models/ServerDTO'; 8 | 9 | export class WorkflowService { 10 | public static async updateEvents(eventUri: Uri) { 11 | const server = await ServerService.getSelect(); 12 | 13 | if (!server) { 14 | return; 15 | } 16 | 17 | try { 18 | await UtilsService.validateServerHasFluiggersWidget(server); 19 | } catch (error: any) { 20 | window.showErrorMessage(error.message || error); 21 | return; 22 | } 23 | 24 | const processId: string = eventUri.path.replace(/.*\/workflow\/scripts\/([^.]+).+\.js$/, "$1"); 25 | 26 | const lastProcessVersion: number = await WorkflowService.getLastWorkflowVersion(server, processId); 27 | 28 | if (lastProcessVersion === 0) { 29 | window.showErrorMessage("Processo não foi encontrado no servidor Fluig."); 30 | return; 31 | } 32 | 33 | const processVersionToUpdate: number = parseInt( 34 | await window.showInputBox( 35 | { 36 | prompt: `Qual Versão do Processo pretende atualizar? (última versão: ${lastProcessVersion})`, 37 | value: lastProcessVersion.toString() 38 | } 39 | ) 40 | || "0" 41 | ); 42 | 43 | if (processVersionToUpdate === 0) { 44 | return; 45 | } 46 | 47 | const updateMultipleChoice = await window.showQuickPick( 48 | [ 49 | { label: "Não" , value: false }, 50 | { label: "Sim" , value: true }, 51 | ], 52 | { placeHolder: "Deseja atualizar múltiplos eventos?"} 53 | ); 54 | 55 | if (!updateMultipleChoice) { 56 | return; 57 | } 58 | 59 | const selectedEventsToUpdate = []; 60 | 61 | if (updateMultipleChoice.value) { 62 | selectedEventsToUpdate.push(...await WorkflowService.getEventsToUpdate(processId)) 63 | 64 | if (!selectedEventsToUpdate.length) { 65 | return; 66 | } 67 | } else { 68 | selectedEventsToUpdate.push({ 69 | label: eventUri.path.replace(/.*\/workflow\/scripts\/[^.]+\.([^.]+)\.js$/, "$1"), 70 | path: eventUri.fsPath, 71 | }); 72 | } 73 | 74 | if (server.confirmExporting && !(await UtilsService.confirmPassword(server))) { 75 | return; 76 | } 77 | 78 | const eventsToUpdate = []; 79 | 80 | for (const event of selectedEventsToUpdate) { 81 | eventsToUpdate.push({ 82 | name: event.label, 83 | contents: readFileSync(event.path, "utf8") 84 | }); 85 | } 86 | 87 | try { 88 | const response: any = await fetch( 89 | `${UtilsService.getHost(server)}/fluiggersWidget/api/workflows/${encodeURIComponent(processId)}/${processVersionToUpdate}/events`, 90 | { 91 | method: "PUT", 92 | headers: { 93 | "Cookie": await LoginService.loginAndGetCookies(server), 94 | "Content-Type": "application/json", 95 | }, 96 | body: JSON.stringify(eventsToUpdate), 97 | } 98 | ) 99 | .then(r => { 100 | if (!r.ok) { 101 | throw `Não foi possível atualizar os eventos. ${r.statusText}`; 102 | } 103 | 104 | return r.json(); 105 | }); 106 | 107 | if (!response.hasError) { 108 | window.showInformationMessage("Todos os eventos foram atualizados"); 109 | return; 110 | } 111 | 112 | window.showWarningMessage( 113 | "Ocorreram erros ao atualizar os eventos", 114 | { 115 | detail: response.errors.join("\n"), 116 | modal: true, 117 | } 118 | ); 119 | 120 | } catch (error: any) { 121 | window.showErrorMessage(error.message || error); 122 | } 123 | } 124 | 125 | public static async getEventsToUpdate(processId: string) { 126 | const eventsFolderUri = Uri.joinPath(UtilsService.getWorkspaceUri(), "workflow", "scripts"); 127 | 128 | const allEvents = glob.sync(`${eventsFolderUri.fsPath}/${processId}.*.js`).map(path => { 129 | return { 130 | label: path.replace(/.*[/\\]+workflow[/\\]+scripts[/\\]+[^.]+\.([^.]+)\.js$/, "$1"), 131 | path: path, 132 | }; 133 | }); 134 | 135 | allEvents.sort((a, b) => a.label.localeCompare(b.label)); 136 | 137 | return await window.showQuickPick(allEvents, { 138 | placeHolder: "Selecione os eventos para atualizar", 139 | canPickMany: true 140 | }) || []; 141 | } 142 | 143 | public static async getLastWorkflowVersion(server: ServerDTO, processId: string): Promise { 144 | return await fetch( 145 | `${UtilsService.getHost(server)}/fluiggersWidget/api/workflows/${encodeURIComponent(processId)}/version`, 146 | { 147 | method: "GET", 148 | headers: { 'Cookie': await LoginService.loginAndGetCookies(server) } 149 | } 150 | ) 151 | .then(async r => { 152 | if (!r.ok) { 153 | return 0; 154 | } 155 | 156 | const version = await r.text(); 157 | return parseInt(version); 158 | }); 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/views/DatasetView.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import * as fs from 'fs'; 3 | import { Server } from '../models/Server'; 4 | import { DatasetService } from '../services/DatasetService'; 5 | const compile = require('template-literal'); 6 | 7 | export class DatasetView { 8 | 9 | private currentPanel: vscode.WebviewPanel | undefined = undefined; 10 | private server: Server; 11 | 12 | constructor(private context: vscode.ExtensionContext, server: Server) { 13 | this.server = server; 14 | } 15 | 16 | public show() { 17 | this.currentPanel = this.createWebViewPanel(); 18 | this.currentPanel.webview.html = this.getWebViewContent(); 19 | this.currentPanel.onDidDispose( 20 | () => this.currentPanel = undefined, 21 | null 22 | ); 23 | this.currentPanel.webview.onDidReceiveMessage( 24 | obj => this.messageListener(obj), 25 | undefined 26 | ); 27 | } 28 | 29 | private getWebViewContent() { 30 | const htmlPath = vscode.Uri.joinPath(this.context.extensionUri, 'dist', 'views', 'dataset', 'dataset.html'); 31 | const runTemplate = compile(fs.readFileSync(htmlPath.with({ scheme: 'vscode-resource' }).fsPath)); 32 | 33 | return runTemplate({ 34 | jquery: this.currentPanel?.webview.asWebviewUri(vscode.Uri.joinPath(this.context.extensionUri, 'dist', 'libs', 'jquery.min.js')), 35 | bootstrapCss: this.currentPanel?.webview.asWebviewUri(vscode.Uri.joinPath(this.context.extensionUri, 'dist', 'libs', 'bootstrap.min.css')), 36 | bootstrapJs: this.currentPanel?.webview.asWebviewUri(vscode.Uri.joinPath(this.context.extensionUri, 'dist', 'libs', 'bootstrap.min.js')), 37 | select2Css: this.currentPanel?.webview.asWebviewUri(vscode.Uri.joinPath(this.context.extensionUri, 'dist', 'libs', 'select2.min.css')), 38 | select2Js: this.currentPanel?.webview.asWebviewUri(vscode.Uri.joinPath(this.context.extensionUri, 'dist', 'libs', 'select2.min.js')), 39 | datatablesCss: this.currentPanel?.webview.asWebviewUri(vscode.Uri.joinPath(this.context.extensionUri, 'dist', 'libs', 'datatables.min.css')), 40 | datatablesJs: this.currentPanel?.webview.asWebviewUri(vscode.Uri.joinPath(this.context.extensionUri, 'dist', 'libs', 'datatables.min.js')), 41 | html5SortableJs: this.currentPanel?.webview.asWebviewUri(vscode.Uri.joinPath(this.context.extensionUri, 'dist', 'libs', 'html5sortable.min.js')), 42 | themeCss: this.currentPanel?.webview.asWebviewUri(vscode.Uri.joinPath(this.context.extensionUri, 'dist', 'css', 'theme.css')), 43 | datasetCss: this.currentPanel?.webview.asWebviewUri(vscode.Uri.joinPath(this.context.extensionUri, 'dist', 'views', 'dataset', 'dataset.css')), 44 | datasetJs: this.currentPanel?.webview.asWebviewUri(vscode.Uri.joinPath(this.context.extensionUri, 'dist', 'views', 'dataset', 'dataset.js')), 45 | serverName: this.server.name 46 | }); 47 | } 48 | 49 | private createWebViewPanel() { 50 | return vscode.window.createWebviewPanel( 51 | "fluig-vscode-extension.consultarDataset", 52 | `${this.server.name}: Consultar Dataset`, 53 | vscode.ViewColumn.One, 54 | { 55 | enableScripts: true, 56 | localResourceRoots: [this.context.extensionUri], 57 | retainContextWhenHidden: true 58 | } 59 | ); 60 | } 61 | 62 | private messageListener(obj: any) { 63 | switch(obj.command) { 64 | case 'consult_dataset': 65 | this.consultDataset(obj); 66 | break; 67 | 68 | case 'load_datasets': 69 | this.loadDatasets(); 70 | break; 71 | 72 | case 'error': 73 | vscode.window.showErrorMessage(obj.message); 74 | break; 75 | } 76 | } 77 | 78 | private async loadDatasets() { 79 | if (!this.currentPanel) { 80 | return; 81 | } 82 | 83 | try { 84 | let datasets = await DatasetService.getDatasets(this.server); 85 | let datasetOptions = []; 86 | 87 | for (let dataset of datasets) { 88 | datasetOptions.push({ 89 | id: dataset.datasetId, 90 | text: dataset.datasetId 91 | }); 92 | } 93 | 94 | this.currentPanel.webview.postMessage({ 95 | command: 'load_datasets', 96 | datasets: datasetOptions 97 | }); 98 | } catch(err: any) { 99 | const message = (err instanceof Error) ? err.message : err; 100 | 101 | this.currentPanel.webview.postMessage({ 102 | command: 'error', 103 | message: message, 104 | }); 105 | 106 | vscode.window.showErrorMessage(`Erro ao carregar os datasets do servidor ${this.server.name}.\nErro retornado: ${message}`); 107 | } 108 | } 109 | 110 | private async consultDataset(queryInformation: any) { 111 | if (!this.currentPanel || !queryInformation) { 112 | return; 113 | } 114 | 115 | try { 116 | const queryResult = await DatasetService.getResultDataset( 117 | this.server, 118 | queryInformation.datasetId, 119 | queryInformation.fields, 120 | queryInformation.constraints, 121 | queryInformation.order 122 | ); 123 | 124 | this.currentPanel.webview.postMessage({ 125 | command: 'query_result', 126 | queryResult: queryResult 127 | }); 128 | 129 | } catch(err: any) { 130 | const message = (err instanceof Error) ? err.message : err; 131 | 132 | this.currentPanel.webview.postMessage({ 133 | command: 'error', 134 | message: message, 135 | }); 136 | 137 | vscode.window.showErrorMessage(`Erro ao consultar o Dataset ${queryInformation.datasetId}.\nErro retornado: ${message}`); 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/extensions/WorkflowExtension.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { UtilsService } from "../services/UtilsService"; 3 | import { readFileSync } from "fs"; 4 | import { TemplateService } from "../services/TemplateService"; 5 | import { AttributionMechanismService } from '../services/AttributionMechanismService'; 6 | import { WorkflowService } from '../services/WorkflowService'; 7 | 8 | export class WorkflowExtension { 9 | 10 | public static activate(context: vscode.ExtensionContext): void { 11 | context.subscriptions.push(vscode.commands.registerCommand( 12 | "fluiggers-fluig-vscode-extension.newWorkflowEvent", 13 | WorkflowExtension.createWorkflowEvent 14 | )); 15 | context.subscriptions.push(vscode.commands.registerCommand( 16 | "fluiggers-fluig-vscode-extension.updateWorkflowEvent", 17 | WorkflowExtension.updateWorkflowEvent 18 | )); 19 | context.subscriptions.push(vscode.commands.registerCommand( 20 | "fluiggers-fluig-vscode-extension.newMechanism", 21 | WorkflowExtension.createMechanism 22 | )); 23 | context.subscriptions.push(vscode.commands.registerCommand( 24 | "fluiggers-fluig-vscode-extension.importManyMechanisms", 25 | AttributionMechanismService.importMany 26 | )); 27 | context.subscriptions.push(vscode.commands.registerCommand( 28 | "fluiggers-fluig-vscode-extension.importMechanism", 29 | AttributionMechanismService.import 30 | )); 31 | context.subscriptions.push(vscode.commands.registerCommand( 32 | "fluiggers-fluig-vscode-extension.exportMechanism", 33 | WorkflowExtension.exportMechanism 34 | )); 35 | } 36 | 37 | /** 38 | * Cria um Evento de Processo 39 | */ 40 | private static async createWorkflowEvent(folderUri: vscode.Uri) { 41 | // Ativado pelo Atalho 42 | if (!folderUri) { 43 | if (!vscode.window.activeTextEditor) { 44 | vscode.window.showErrorMessage("Não há editor de texto ativo com Processo ou Evento de Processo"); 45 | return; 46 | } 47 | folderUri = vscode.window.activeTextEditor.document.uri; 48 | } 49 | 50 | if (!folderUri.path.endsWith(".process") && !folderUri.path.endsWith(".js")) { 51 | vscode.window.showErrorMessage("Necessário selecionar um Processo ou Evento de Processo para criar o Evento."); 52 | return; 53 | } 54 | 55 | const newFunctionOption = 'Nova Função'; 56 | 57 | let eventName: string = await vscode.window.showQuickPick( 58 | TemplateService.workflowEventsNames.concat(newFunctionOption), 59 | { 60 | canPickMany: false, 61 | placeHolder: "Selecione o Evento" 62 | } 63 | ) || ""; 64 | 65 | if (!eventName) { 66 | return; 67 | } 68 | 69 | let isNewFunction = false; 70 | 71 | if (eventName === newFunctionOption) { 72 | eventName = await vscode.window.showInputBox({ 73 | prompt: "Qual o nome da Nova Função (sem espaços e sem caracteres especiais)?", 74 | placeHolder: "nomeFuncao" 75 | }) || ""; 76 | 77 | if (!eventName) { 78 | return; 79 | } 80 | 81 | isNewFunction = true; 82 | } 83 | 84 | const processName: string = 85 | folderUri.path.endsWith(".process") 86 | ? folderUri.path.replace(/.*\/workflow\/diagrams\/([^.]+)\.process$/, "$1") 87 | : folderUri.path.replace(/.*\/workflow\/scripts\/([^.]+).+\.js$/, "$1"); 88 | 89 | const eventFilename = `${processName}.${eventName}.js`; 90 | const eventUri = vscode.Uri.joinPath( 91 | UtilsService.getWorkspaceUri(), 92 | "workflow", 93 | "scripts", 94 | eventFilename 95 | ); 96 | 97 | try { 98 | // Se Evento já existe carrega o arquivo no editor 99 | await vscode.workspace.fs.stat(eventUri); 100 | return vscode.window.showTextDocument(eventUri); 101 | } catch (err) { 102 | 103 | } 104 | 105 | await vscode.workspace.fs.writeFile( 106 | eventUri, 107 | isNewFunction 108 | ? Buffer.from(TemplateService.createEmptyFunction(eventName), "utf-8") 109 | : readFileSync(vscode.Uri.joinPath(TemplateService.workflowEventsUri, `${eventName}.txt`).fsPath) 110 | ); 111 | vscode.window.showTextDocument(eventUri); 112 | } 113 | 114 | /** 115 | * Atualiza um ou mais eventos de processo 116 | */ 117 | private static async updateWorkflowEvent(fileUri: vscode.Uri) { 118 | // Ativado pelo Atalho 119 | if (!fileUri) { 120 | if (!vscode.window.activeTextEditor) { 121 | vscode.window.showErrorMessage("Não há editor de texto ativo com um Evento de Processo"); 122 | return; 123 | } 124 | fileUri = vscode.window.activeTextEditor.document.uri; 125 | } 126 | 127 | if (!fileUri.path.endsWith(".js")) { 128 | vscode.window.showErrorMessage("Necessário selecionar um Evento de Processo."); 129 | return; 130 | } 131 | 132 | WorkflowService.updateEvents(fileUri); 133 | } 134 | 135 | /** 136 | * Cria um arquivo contendo um novo Mecanismo customizado 137 | */ 138 | private static async createMechanism() { 139 | let mechanism: string = await vscode.window.showInputBox({ 140 | prompt: "Qual o nome do Mecanismo Customizado (sem espaços e sem caracteres especiais)?", 141 | placeHolder: "mecanismo_customizado" 142 | }) || ""; 143 | 144 | if (!mechanism) { 145 | return; 146 | } 147 | 148 | if (!mechanism.endsWith(".js")) { 149 | mechanism += ".js"; 150 | } 151 | 152 | const mechanismUri = vscode.Uri.joinPath(UtilsService.getWorkspaceUri(), "mechanisms", mechanism); 153 | 154 | try { 155 | // Se Mecanismo já existe carrega o arquivo no editor 156 | await vscode.workspace.fs.stat(mechanismUri); 157 | return vscode.window.showTextDocument(mechanismUri); 158 | } catch (err) { 159 | 160 | } 161 | 162 | await vscode.workspace.fs.writeFile( 163 | mechanismUri, 164 | readFileSync(vscode.Uri.joinPath(TemplateService.templatesUri, 'createMechanism.txt').fsPath) 165 | ); 166 | vscode.window.showTextDocument(mechanismUri); 167 | } 168 | 169 | private static exportMechanism(fileUri: vscode.Uri) { 170 | // Ativado pela Tecla de Atalho 171 | if (!fileUri) { 172 | if (!vscode.window.activeTextEditor) { 173 | vscode.window.showErrorMessage("Não há editor de texto ativo com Mecanismo Customizado"); 174 | return; 175 | } 176 | fileUri = vscode.window.activeTextEditor.document.uri; 177 | } 178 | 179 | AttributionMechanismService.export(fileUri); 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /resources/views/dataset/dataset.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Consultar Dataset 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |

${d.serverName}: Consultar Dataset

17 |
18 |
19 | 22 |
23 |
24 | 25 | 26 |
27 |
28 | 29 |
30 | 31 | 32 | 121 | 122 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /src/services/ServerService.ts: -------------------------------------------------------------------------------- 1 | import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'fs'; 2 | import { window, Uri, QuickPickItem } from "vscode"; 3 | import { UtilsService } from "./UtilsService"; 4 | import { ServerConfig } from "../models/ServerConfig"; 5 | import { ServerDTO } from "../models/ServerDTO"; 6 | import { Server } from "../models/Server"; 7 | import { UserService } from './UserService'; 8 | 9 | const SERVER_CONFIG_VERSION = '1.0.0'; 10 | 11 | export class ServerService { 12 | private static PATH = Uri.joinPath(UtilsService.getWorkspaceUri(), '.vscode').fsPath; 13 | private static FILE_SERVER_CONFIG = Uri.joinPath(UtilsService.getWorkspaceUri(), '.vscode', 'servers.json').fsPath; 14 | private static SELECTED_SERVER: string = ""; 15 | 16 | /** 17 | * Adiciona um novo servidor 18 | */ 19 | public static create(server: ServerDTO) { 20 | const serverConfig = ServerService.getServerConfig(); 21 | 22 | if (!serverConfig.configurations) { 23 | return null; 24 | } 25 | 26 | server.id = UtilsService.generateRandomID(); 27 | serverConfig.configurations.push(server); 28 | ServerService.writeServerConfig(serverConfig); 29 | 30 | return server; 31 | } 32 | 33 | /** 34 | * Remove um servidor 35 | */ 36 | public static delete(id: string) { 37 | const serverConfig = ServerService.getServerConfig(); 38 | 39 | if (!serverConfig.configurations) { 40 | return; 41 | } 42 | 43 | const servers = serverConfig.configurations; 44 | servers.forEach((element: ServerDTO) => { 45 | if (element.id === id) { 46 | const index = servers.indexOf(element, 0); 47 | servers.splice(index, 1); 48 | ServerService.writeServerConfig(serverConfig); 49 | return; 50 | } 51 | }); 52 | } 53 | 54 | /** 55 | * Atualizar dados do servidor 56 | */ 57 | public static update(server: ServerDTO) { 58 | const serverConfig = ServerService.getServerConfig(); 59 | 60 | if (!serverConfig.configurations) { 61 | return; 62 | } 63 | 64 | const servers = serverConfig.configurations; 65 | servers.forEach((element: ServerDTO) => { 66 | if (element.id === server.id) { 67 | const index = servers.indexOf(element, 0); 68 | servers.splice(index, 1); 69 | servers.push(server); 70 | ServerService.writeServerConfig(serverConfig); 71 | return; 72 | } 73 | }); 74 | } 75 | 76 | public static createOrUpdate(server: ServerDTO) { 77 | if (server.id) { 78 | this.update(server); 79 | } else { 80 | this.create(server); 81 | } 82 | } 83 | 84 | public static findByName(name: string): ServerDTO|undefined { 85 | const servers = ServerService.getServerConfig(); 86 | return servers.configurations.find(server => server.name === name); 87 | } 88 | 89 | public static findById(id: string): ServerDTO|undefined { 90 | const servers = ServerService.getServerConfig(); 91 | return servers.configurations.find(server => server.id === id); 92 | } 93 | 94 | public static async getSelect() { 95 | const servers = ServerService.getServersLabels(); 96 | 97 | const result = await window.showQuickPick(servers, { 98 | placeHolder: "Selecione o servidor", 99 | }); 100 | 101 | if (!result) { 102 | return; 103 | } 104 | 105 | ServerService.SELECTED_SERVER = result.label; 106 | 107 | return new Server(ServerService.findByName(result.label)); 108 | } 109 | 110 | private static getServersLabels() { 111 | const serversConfig = ServerService.getServerConfig(); 112 | const serversLabels: QuickPickItem[] = []; 113 | let hasSelectedServer = false; 114 | 115 | for (let i = 0; i < serversConfig.configurations.length; ++i) { 116 | const serverName = serversConfig.configurations[i].name; 117 | 118 | if (serverName === ServerService.SELECTED_SERVER) { 119 | hasSelectedServer = true; 120 | continue; 121 | } 122 | serversLabels.push({ label: serverName }); 123 | } 124 | 125 | if (hasSelectedServer) { 126 | serversLabels.unshift({ label: ServerService.SELECTED_SERVER}); 127 | } 128 | 129 | return serversLabels; 130 | } 131 | 132 | /** 133 | * Retorna o caminho do arquivo Server Config 134 | */ 135 | public static getFileServerConfig(): string { 136 | if (!existsSync(ServerService.FILE_SERVER_CONFIG)) { 137 | ServerService.createServerConfig(); 138 | } 139 | 140 | return ServerService.FILE_SERVER_CONFIG; 141 | } 142 | 143 | /** 144 | * Cria o arquivo de configuração dos servidores 145 | */ 146 | private static createServerConfig() { 147 | const serverConfig: ServerConfig = { 148 | version: SERVER_CONFIG_VERSION, 149 | configurations: [] 150 | }; 151 | 152 | if (!existsSync(ServerService.PATH)) { 153 | mkdirSync(ServerService.PATH); 154 | } 155 | 156 | writeFileSync(ServerService.FILE_SERVER_CONFIG, JSON.stringify(serverConfig, null, "\t")); 157 | } 158 | 159 | /** 160 | * Criar / Alterar o arquivo de servidores 161 | */ 162 | private static writeServerConfig(serverConfig: ServerConfig) { 163 | writeFileSync(ServerService.FILE_SERVER_CONFIG, JSON.stringify(serverConfig, null, "\t")); 164 | } 165 | 166 | /** 167 | * Leitura do arquivo Server Config 168 | */ 169 | public static getServerConfig(): ServerConfig { 170 | if (!existsSync(ServerService.FILE_SERVER_CONFIG)) { 171 | ServerService.createServerConfig(); 172 | } 173 | 174 | return JSON.parse(readFileSync(ServerService.FILE_SERVER_CONFIG).toString()); 175 | } 176 | 177 | public static async checkServerConfigVersion() { 178 | let serverConfig = ServerService.getServerConfig(); 179 | 180 | if (serverConfig.version === SERVER_CONFIG_VERSION) { 181 | return true; 182 | } 183 | 184 | if (!serverConfig.configurations.length) { 185 | ServerService.createServerConfig(); 186 | return true; 187 | } 188 | 189 | const answer = await window.showWarningMessage( 190 | "Arquivo de Configuração está Desatualizado.", 191 | { 192 | detail: "Para atualizar o arquivo você terá que digitar a senha de todos os servidores (aconselhável fazer backup antes).\n\nDeseja continuar?.", 193 | modal: true, 194 | }, 195 | "Sim" 196 | ); 197 | 198 | if (answer !== "Sim") { 199 | return false; 200 | } 201 | 202 | for (const serverDto of serverConfig.configurations) { 203 | const server = new Server(serverDto); 204 | server.password = (await window.showInputBox({ 205 | prompt: `Digite a senha do usuário ${server.username} no servidor ${server.name}`, 206 | ignoreFocusOut: true, 207 | password: true, 208 | placeHolder: "Digite a senha", 209 | })) || ""; 210 | 211 | try { 212 | const response:any = await UserService.getUser(server); 213 | 214 | if (!response.content) { 215 | window.showWarningMessage(`Erro ao salvar senha do servidor ${server.name}.`); 216 | } 217 | 218 | ServerService.update(server); 219 | } catch (e) { 220 | window.showErrorMessage(`Falha na conexão com o servidor ${server.name}.\nErro retornado: ${e}`); 221 | } 222 | } 223 | 224 | serverConfig = ServerService.getServerConfig(); 225 | 226 | serverConfig.version = SERVER_CONFIG_VERSION; 227 | ServerService.writeServerConfig(serverConfig); 228 | 229 | return true; 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /resources/css/theme.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: var(--vscode-editor-background); 3 | color: var(--vscode-editor-foreground); 4 | font-family: var(--vscode-font-family); 5 | font-size: var(--vscode-editor-font-size); 6 | } 7 | 8 | body.vscode-dark .form-select, 9 | body.vscode-high-contrast:not(.vscode-high-contrast-light) .form-select { 10 | background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e") 11 | } 12 | 13 | ::placeholder { 14 | color: var(--vscode-input-placeholderForeground); 15 | } 16 | 17 | .form-control, 18 | .form-select, 19 | .select2-container--bootstrap .select2-search--dropdown .select2-search__field { 20 | background-color: var(--vscode-input-background); 21 | color: var(--vscode-input-foreground); 22 | border: 1px solid var(--vscode-input-border, var(--bs-gray)); 23 | font-size: var(--vscode-editor-font-size); 24 | } 25 | 26 | .form-control:focus, 27 | .select2-container--bootstrap .select2-search--dropdown .select2-search__field { 28 | background-color: var(--vscode-input-background); 29 | color: var(--vscode-input-foreground); 30 | border-color: var(--vscode-focusBorder); 31 | } 32 | 33 | .btn-primary { 34 | color: var(--vscode-button-foreground); 35 | background-color: var(--vscode-button-background); 36 | border-color: var(--vscode-button-separator); 37 | } 38 | 39 | .btn-primary:hover, 40 | .btn-primary.focus, 41 | .btn-primary:focus, 42 | .btn-primary:not(:disabled):not(.disabled).active, 43 | .btn-primary:not(:disabled):not(.disabled):active, 44 | .show>.btn-primary.dropdown-toggle { 45 | background-color: var(--vscode-button-hoverBackground, var(--bs-primary)); 46 | border-color: var(--vscode-button-separator); 47 | } 48 | 49 | .btn-secondary { 50 | color: var(--vscode-button-secondaryForeground); 51 | background-color: var(--vscode-button-secondaryBackground); 52 | border-color: var(--vscode-button-separator); 53 | } 54 | 55 | .btn-secondary:hover, 56 | .btn-secondary.focus, 57 | .btn-secondary:focus, 58 | .btn-secondary:not(:disabled):not(.disabled).active, 59 | .btn-secondary:not(:disabled):not(.disabled):active, 60 | .show>.btn-secondary.dropdown-toggle { 61 | border-color: var(--vscode-button-separator); 62 | color: var(--vscode-button-secondaryForeground); 63 | background-color: var(--vscode-button-hoverBackground, var(--bs-secondary)); 64 | } 65 | 66 | .btn.disabled, 67 | .btn:disabled, 68 | fieldset:disabled .btn { 69 | color: inherit; 70 | pointer-events: none; 71 | background-color: inherit; 72 | border-color: inherit; 73 | } 74 | 75 | .select2-container--default .select2-selection--single { 76 | background-color: var(--vscode-editor-background); 77 | border: 1px solid var(--vscode-input-border, var(--bs-gray)); 78 | } 79 | 80 | .select2-container--default .select2-selection--single .select2-selection__arrow b { 81 | border-color: var(--vscode-editor-foreground, var(--bs-gray)) transparent transparent transparent; 82 | } 83 | 84 | .select2-dropdown { 85 | background-color: var(--vscode-editor-background); 86 | border: 1px solid var(--vscode-input-border, var(--bs-gray)); 87 | } 88 | 89 | .select2-container--default .select2-search--dropdown .select2-search__field { 90 | background-color: var(--vscode-editor-background); 91 | color: var(--vscode-editor-foreground); 92 | border: 1px solid var(--vscode-input-border, var(--bs-gray)); 93 | } 94 | 95 | .select2-container--default .select2-results__option--highlighted.select2-results__option--selectable, 96 | .select2-container--default .select2-results__option--selected { 97 | background-color: var(--vscode-button-hoverBackground, var(--bs-primary)); 98 | color: var(--vscode-button-foreground); 99 | } 100 | 101 | .select2-container .select2-selection--single { 102 | height: 38px; 103 | } 104 | 105 | .select2-container--default .select2-selection--single .select2-selection__rendered { 106 | color: var(--vscode-editor-foreground); 107 | line-height: 33px; 108 | } 109 | 110 | .select2-container--default .select2-selection--single .select2-selection__arrow { 111 | height: 35px; 112 | } 113 | 114 | 115 | .page-link { 116 | background-color: var(--vscode-button-hoverBackground, var(--bs-primary)); 117 | color: var(--vscode-button-foreground); 118 | border: 1px solid var(--vscode-input-border, var(--bs-gray)); 119 | } 120 | 121 | .page-link:hover { 122 | background-color: var(--vscode-button-background); 123 | color: var(--vscode-button-foreground); 124 | border: 1px solid var(--vscode-input-border, var(--bs-gray)); 125 | } 126 | 127 | .page-item.disabled .page-link { 128 | color: var(--vscode-disabledForeground); 129 | background-color: var(--vscode-tab-inactiveBackground); 130 | border: 1px solid var(--vscode-input-border, var(--bs-gray)); 131 | } 132 | 133 | /* .table thead th, 134 | .table tbody td { 135 | border-bottom: 1px solid var(--vscode-input-border, var(--bs-gray)); 136 | } */ 137 | 138 | div.dt-button-info { 139 | background-color: var(--vscode-editor-background); 140 | border: 2px solid var(--vscode-input-border, var(--bs-gray)); 141 | } 142 | 143 | div.dt-button-info h2 { 144 | border-bottom: 1px solid #ddd; 145 | background-color: var(--vscode-editor-background); 146 | } 147 | 148 | /* .table-bordered, 149 | .table-bordered td, 150 | .table-bordered th { 151 | border: 1px solid var(--vscode-input-border, var(--bs-gray)); 152 | } */ 153 | 154 | .table { 155 | --bs-table-color: var(--vscode-editor-foreground); 156 | --bs-table-bg: var(--vscode-editor-background); 157 | --bs-table-border-color: var(--vscode-input-border); 158 | --bs-table-striped-color: var(--vscode-editor-foreground); 159 | --bs-table-striped-bg: rgba(var(--vscode-editor-background), 0.1); 160 | --bs-table-active-color: var(--vscode-editor-foreground); 161 | --bs-table-active-bg: rgba(var(--vscode-editor-background), 0.1); 162 | --bs-table-hover-color: var(---vscode-editor-foreground); 163 | --bs-table-hover-bg: rgba(var(--vscode-editor-background), 0.2); 164 | } 165 | 166 | table.dataTable.table-striped>tbody>tr:nth-of-type(2n+1)>* { 167 | box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-stripe), 0.18); 168 | } 169 | 170 | .modal-title, .modal-body { 171 | color: var(--vscode-editor-foreground) !important; 172 | } 173 | 174 | .modal-header { 175 | border-bottom-color: var(--vscode-input-border, var(--bs-gray)); 176 | } 177 | 178 | .modal-header .close { 179 | color: var(--vscode-editor-foreground); 180 | } 181 | 182 | .modal-content, 183 | .tab-content { 184 | background-color: var(--vscode-editor-background); 185 | border: 1px solid var(--vscode-input-border, var(--bs-gray)); 186 | } 187 | 188 | .tab-content { 189 | border-top: none; 190 | } 191 | 192 | .nav-tabs { 193 | border-bottom: 1px solid var(--vscode-input-border, var(--bs-gray)); 194 | } 195 | 196 | .nav-tabs .nav-link { 197 | background-color: var(--vscode-tab-inactiveBackground); 198 | color: var(--vscode-tab-inactiveForeground); 199 | border: 1px solid var(--vscode-input-border, var(--bs-gray)); 200 | } 201 | 202 | .nav-tabs .nav-link.active { 203 | background-color: var(--vscode-tab-activeBackground); 204 | color: var(--vscode-tab-activeForeground); 205 | border: 1px solid var(--vscode-input-border, var(--bs-gray)); 206 | border-bottom-color: transparent; 207 | } 208 | 209 | .nav-tabs .nav-link:focus, 210 | .nav-tabs .nav-link:hover { 211 | border-color: var(--vscode-input-border, var(--bs-gray)) var(--vscode-input-border, var(--bs-gray)) var(--vscode-input-border, var(--bs-gray)); 212 | } 213 | 214 | table.dataTable thead>tr>th.sorting:before, 215 | table.dataTable thead>tr>th.sorting:after, 216 | table.dataTable thead>tr>th.sorting_asc:before, 217 | table.dataTable thead>tr>th.sorting_asc:after, 218 | table.dataTable thead>tr>th.sorting_desc:before, 219 | table.dataTable thead>tr>th.sorting_desc:after, 220 | table.dataTable thead>tr>th.sorting_asc_disabled:before, 221 | table.dataTable thead>tr>th.sorting_asc_disabled:after, 222 | table.dataTable thead>tr>th.sorting_desc_disabled:before, 223 | table.dataTable thead>tr>th.sorting_desc_disabled:after, 224 | table.dataTable thead>tr>td.sorting:before, 225 | table.dataTable thead>tr>td.sorting:after, 226 | table.dataTable thead>tr>td.sorting_asc:before, 227 | table.dataTable thead>tr>td.sorting_asc:after, 228 | table.dataTable thead>tr>td.sorting_desc:before, 229 | table.dataTable thead>tr>td.sorting_desc:after, 230 | table.dataTable thead>tr>td.sorting_asc_disabled:before, 231 | table.dataTable thead>tr>td.sorting_asc_disabled:after, 232 | table.dataTable thead>tr>td.sorting_desc_disabled:before, 233 | table.dataTable thead>tr>td.sorting_desc_disabled:after { 234 | opacity: 0.6; 235 | } 236 | 237 | table.dataTable thead>tr>th.sorting_asc:before, 238 | table.dataTable thead>tr>th.sorting_desc:after, 239 | table.dataTable thead>tr>td.sorting_asc:before, 240 | table.dataTable thead>tr>td.sorting_desc:after { 241 | opacity: 1; 242 | } 243 | 244 | body.vscode-dark .modal-header .btn-close, 245 | body.vscode-high-contrast:not(.vscode-high-contrast-light) .modal-header .btn-close { 246 | filter: invert(1) grayscale(100%) brightness(200%); 247 | } 248 | 249 | .dtfh-floatingparent.dtfh-floatingparenthead table { 250 | background-color: var(--vscode-editor-background) !important; 251 | } 252 | 253 | div.dt-scroll-body { 254 | border-bottom-color: var(--vscode-input-border); 255 | } 256 | -------------------------------------------------------------------------------- /src/services/GlobalEventService.ts: -------------------------------------------------------------------------------- 1 | import { ServerDTO } from "../models/ServerDTO"; 2 | import { UtilsService } from "./UtilsService"; 3 | import { GlobalEventDTO } from "../models/GlobalEventDTO"; 4 | import { window, workspace, Uri, ProgressLocation } from "vscode"; 5 | import { ServerService } from "./ServerService"; 6 | import { basename } from "path"; 7 | import { readFileSync } from "fs"; 8 | import {LoginService} from "./LoginService"; 9 | 10 | const basePath = "/ecm/api/rest/ecm/globalevent/"; 11 | 12 | const headers = new Headers({ 13 | "Accept": "application/json", 14 | "Content-Type": "application/json", 15 | 16 | }); 17 | 18 | export class GlobalEventService { 19 | /** 20 | * Retorna uma lista com todos os eventos globais 21 | */ 22 | private static async getEventList(server: ServerDTO): Promise { 23 | try { 24 | headers.set('Cookie', await LoginService.loginAndGetCookies(server)); 25 | const response:any = await fetch( 26 | UtilsService.getRestUrl(server, basePath, "getEventList"), 27 | { headers } 28 | ).then(r => r.json()); 29 | 30 | if (response.message) { 31 | window.showErrorMessage(response.message.message); 32 | return []; 33 | } 34 | 35 | return response; 36 | } catch (error: any) { 37 | window.showErrorMessage(error.message || error); 38 | } 39 | 40 | return []; 41 | } 42 | 43 | private static async saveEventList(server: ServerDTO, globalEvents: GlobalEventDTO[]) { 44 | const requestOptions = { 45 | method: 'post', 46 | headers: { 47 | "Accept": "application/json", 48 | "Content-Type": "application/x-www-form-urlencoded", 49 | 'Cookie': await LoginService.loginAndGetCookies(server) 50 | }, 51 | body: JSON.stringify(globalEvents), 52 | }; 53 | 54 | try { 55 | return await fetch( 56 | UtilsService.getRestUrl(server, basePath, "saveEventList"), 57 | requestOptions 58 | ).then(r => r.json()); 59 | } catch (error: any) { 60 | window.showErrorMessage(error.message || error); 61 | } 62 | } 63 | 64 | /** 65 | * Retorna o evento global selecionado 66 | */ 67 | private static async getOptionSelected(server: ServerDTO): Promise { 68 | const eventList = await GlobalEventService.getEventList(server); 69 | const items = eventList.map(event => ({ label: event.globalEventPK.eventId })); 70 | const result = await window.showQuickPick(items, { 71 | placeHolder: "Selecione o evento" 72 | }); 73 | 74 | if (!result) { 75 | return; 76 | } 77 | 78 | return eventList.find(event => event.globalEventPK.eventId === result.label); 79 | } 80 | 81 | /** 82 | * Retorna o evento global selecionado 83 | */ 84 | private static async getOptionsSelected(server: ServerDTO): Promise { 85 | const eventList = await GlobalEventService.getEventList(server); 86 | const items = eventList.map(event => ({ label: event.globalEventPK.eventId })); 87 | const result = await window.showQuickPick(items, { 88 | placeHolder: "Selecione os eventos", 89 | canPickMany: true 90 | }); 91 | 92 | if (!result) { 93 | return; 94 | } 95 | 96 | const retEventList: GlobalEventDTO[] = []; 97 | for(let item of result) { 98 | for(let event of eventList) { 99 | if(event.globalEventPK.eventId === item.label) { 100 | retEventList.push(event); 101 | } 102 | } 103 | } 104 | 105 | return retEventList; 106 | } 107 | 108 | /** 109 | * Realiza a importação de um evento global 110 | */ 111 | public static async import() { 112 | const server = await ServerService.getSelect(); 113 | 114 | if (!server) { 115 | return; 116 | } 117 | 118 | const event = await GlobalEventService.getOptionSelected(server); 119 | 120 | if (!event) { 121 | return; 122 | } 123 | 124 | GlobalEventService.saveFile( 125 | event.globalEventPK.eventId, 126 | event.eventDescription 127 | ); 128 | } 129 | 130 | /** 131 | * Realiza a importação de vários eventos globais 132 | */ 133 | public static async importMany() { 134 | const server = await ServerService.getSelect(); 135 | 136 | if (!server) { 137 | return; 138 | } 139 | 140 | const eventList = await GlobalEventService.getOptionsSelected(server); 141 | 142 | if (!eventList || !eventList.length) { 143 | return; 144 | } 145 | 146 | const results = await window.withProgress( 147 | { 148 | location: ProgressLocation.Notification, 149 | title: "Importando Eventos Globais.", 150 | cancellable: false 151 | }, 152 | progress => { 153 | const increment = 100 / eventList.length; 154 | let current = 0; 155 | 156 | progress.report({ increment: 0 }); 157 | 158 | return Promise.all(eventList.map(async event => { 159 | GlobalEventService.saveFile( 160 | event.globalEventPK.eventId, 161 | event.eventDescription, 162 | false 163 | ); 164 | current += increment; 165 | progress.report({ increment: current }); 166 | return true; 167 | })); 168 | } 169 | ); 170 | 171 | window.showInformationMessage(`${results.length} Eventos Globais foram importados.`); 172 | } 173 | 174 | public static async export(fileUri: Uri) { 175 | const server = await ServerService.getSelect(); 176 | 177 | if (!server) { 178 | return; 179 | } 180 | 181 | const globalEvents = await GlobalEventService.getEventList(server); 182 | const globalEventId: string = basename(fileUri.fsPath, '.js'); 183 | 184 | const globalEventStructure: GlobalEventDTO = { 185 | globalEventPK: { 186 | companyId: server.companyId, 187 | eventId: globalEventId 188 | }, 189 | eventDescription: readFileSync(fileUri.fsPath, 'utf8') 190 | }; 191 | 192 | const index = globalEvents.findIndex(globalEvent => globalEvent.globalEventPK.eventId === globalEventId); 193 | 194 | if (index === -1) { 195 | globalEvents.push(globalEventStructure); 196 | } else { 197 | globalEvents[index] = globalEventStructure; 198 | } 199 | 200 | let result: any = undefined; 201 | 202 | // Validar senha antes de exportar 203 | if (server.confirmExporting && !(await UtilsService.confirmPassword(server))) { 204 | return; 205 | } 206 | 207 | result = await GlobalEventService.saveEventList(server, globalEvents); 208 | 209 | if (result.content === 'OK') { 210 | window.showInformationMessage(`Evento Global ${globalEventId} exportado com sucesso!`); 211 | } else { 212 | window.showErrorMessage(`Falha ao exportar o Evento Global ${globalEventId}!\n${result?.message?.message}`); 213 | } 214 | } 215 | 216 | public static async delete() { 217 | const server = await ServerService.getSelect(); 218 | 219 | if (!server) { 220 | return; 221 | } 222 | 223 | const eventList = await GlobalEventService.getOptionsSelected(server); 224 | 225 | if (!eventList) { 226 | return; 227 | } 228 | 229 | // Validar senha antes de deletar 230 | if (server.confirmExporting && !(await UtilsService.confirmPassword(server))) { 231 | return; 232 | } 233 | 234 | const url = UtilsService.getRestUrl(server, basePath, "deleteGlobalEvent"); 235 | 236 | eventList.forEach(async event => { 237 | url.searchParams.set("eventName", event.globalEventPK.eventId); 238 | 239 | headers.set('Cookie', await LoginService.loginAndGetCookies(server)); 240 | const result:any = await fetch( 241 | url, 242 | { method: "DELETE", headers } 243 | ).then(r => r.json()); 244 | 245 | if (result.content === "OK") { 246 | window.showInformationMessage(`Evento Global ${event.globalEventPK.eventId} removido com sucesso!`); 247 | } else { 248 | window.showErrorMessage(`Erro ao remover Evento Global ${event.globalEventPK.eventId}!\n${result.message.message}`); 249 | } 250 | }); 251 | } 252 | 253 | /** 254 | * Criar arquivo de evento global 255 | */ 256 | public static async saveFile(name: string, content: string, openFile: boolean = true) { 257 | const uri = Uri.joinPath(UtilsService.getWorkspaceUri(), "events", name + ".js"); 258 | 259 | await workspace.fs.writeFile( 260 | uri, 261 | Buffer.from(content, "utf-8") 262 | ); 263 | 264 | if (openFile) { 265 | window.showTextDocument(uri); 266 | window.showInformationMessage(`Evento global ${name} importado com sucesso!`); 267 | } 268 | } 269 | } 270 | -------------------------------------------------------------------------------- /src/services/AttributionMechanismService.ts: -------------------------------------------------------------------------------- 1 | import { Uri, window, workspace, ProgressLocation } from 'vscode'; 2 | import { basename } from "path"; 3 | import { UtilsService } from './UtilsService'; 4 | import { ServerDTO } from '../models/ServerDTO'; 5 | import { AttributionMechanismDTO } from '../models/AttributionMechanismDTO'; 6 | import { ServerService } from './ServerService'; 7 | import { open, readFileSync } from 'fs'; 8 | import {LoginService} from "./LoginService"; 9 | 10 | const basePath = "/ecm/api/rest/ecm/mechanism/"; 11 | 12 | const headers = new Headers({ 13 | "Accept": "application/json", 14 | "Content-Type": "application/json", 15 | }); 16 | 17 | export class AttributionMechanismService { 18 | private static async list(server: ServerDTO): Promise { 19 | const url = UtilsService.getRestUrl(server, basePath, "getCustomAttributionMechanismList"); 20 | 21 | try { 22 | headers.set('Cookie', await LoginService.loginAndGetCookies(server)); 23 | const response:any = await fetch(url, { headers }).then(r => r.json()); 24 | 25 | if (response.message) { 26 | window.showErrorMessage(response.message.message); 27 | return []; 28 | } 29 | 30 | return response; 31 | } catch (error: any) { 32 | window.showErrorMessage(error.message || error); 33 | } 34 | 35 | return []; 36 | } 37 | 38 | private static async create(server: ServerDTO, mechanism: AttributionMechanismDTO) { 39 | try { 40 | headers.set('Cookie', await LoginService.loginAndGetCookies(server)); 41 | return await fetch( 42 | UtilsService.getRestUrl(server, basePath, "createAttributionMechanism"), 43 | { 44 | headers, 45 | method: "POST", 46 | body: JSON.stringify(mechanism), 47 | } 48 | ).then(r => r.json()); 49 | } catch (error) { 50 | return { 51 | message: { 52 | message: "Erro: " + error 53 | } 54 | }; 55 | } 56 | } 57 | 58 | private static async update(server: ServerDTO, mechanism: AttributionMechanismDTO) { 59 | try { 60 | headers.set('Cookie', await LoginService.loginAndGetCookies(server)); 61 | return await fetch( 62 | UtilsService.getRestUrl(server, basePath, "updateAttributionMechanism"), 63 | { 64 | headers, 65 | method: "POST", 66 | body: JSON.stringify(mechanism), 67 | } 68 | ).then(r => r.json()); 69 | } catch (error) { 70 | return { 71 | message: { 72 | message: "Erro: " + error 73 | } 74 | }; 75 | } 76 | } 77 | 78 | private static async delete(server: ServerDTO, mechanismId: string) { 79 | const url = UtilsService.getRestUrl(server, basePath, "deleteAttributionMechanism", { "mechanismId": mechanismId }); 80 | 81 | try { 82 | headers.set('Cookie', await LoginService.loginAndGetCookies(server)); 83 | return await fetch( 84 | url, 85 | { 86 | headers, 87 | method: "DELETE", 88 | } 89 | ).then(r => r.json()); 90 | } catch (error) { 91 | return { 92 | message: { 93 | message: "Erro: " + error 94 | } 95 | }; 96 | } 97 | } 98 | 99 | /** 100 | * Retorna o mecanismo selecionado 101 | */ 102 | public static async getOptionSelected(server: ServerDTO): Promise { 103 | const mechanisms = await AttributionMechanismService.list(server); 104 | const items = mechanisms.map(mechanism => ({ label: mechanism.attributionMecanismPK.attributionMecanismId, detail: mechanism.name })); 105 | const result = await window.showQuickPick(items, { 106 | placeHolder: "Selecione o Mecanismo de Atribuição" 107 | }); 108 | 109 | if (!result) { 110 | return null; 111 | } 112 | 113 | return mechanisms.find(mechanism => mechanism.attributionMecanismPK.attributionMecanismId === result.label) || null; 114 | } 115 | 116 | /** 117 | * Retorna os mecanismos selecionados 118 | */ 119 | public static async getOptionsSelected(server: ServerDTO): Promise { 120 | const mechanisms = await AttributionMechanismService.list(server); 121 | const items = mechanisms.map(mechanism => ({ label: mechanism.attributionMecanismPK.attributionMecanismId, detail: mechanism.name })); 122 | const result = await window.showQuickPick(items, { 123 | placeHolder: "Selecione o Mecanismo de Atribuição", 124 | canPickMany: true 125 | }); 126 | 127 | if (!result) { 128 | return []; 129 | } 130 | 131 | const itemsSelected = result.map(v => v.label); 132 | 133 | return mechanisms.filter(mechanism => itemsSelected.includes(mechanism.attributionMecanismPK.attributionMecanismId)); 134 | } 135 | 136 | /** 137 | * Realiza a importação de um mecanismo específico 138 | */ 139 | public static async import() { 140 | const server = await ServerService.getSelect(); 141 | 142 | if (!server) { 143 | return; 144 | } 145 | 146 | const mechanism = await AttributionMechanismService.getOptionSelected(server); 147 | 148 | if (!mechanism) { 149 | return; 150 | } 151 | 152 | AttributionMechanismService.saveFile(mechanism.attributionMecanismPK.attributionMecanismId, mechanism.attributionMecanismDescription); 153 | } 154 | 155 | /** 156 | * Realiza a importação de vários mecanismos de atribuição 157 | */ 158 | public static async importMany() { 159 | const server = await ServerService.getSelect(); 160 | 161 | if (!server) { 162 | return; 163 | } 164 | 165 | const mechanisms = await AttributionMechanismService.getOptionsSelected(server); 166 | 167 | if (!mechanisms || !mechanisms.length) { 168 | return; 169 | } 170 | 171 | const results = await window.withProgress( 172 | { 173 | location: ProgressLocation.Notification, 174 | title: "Importando Eventos Globais.", 175 | cancellable: false 176 | }, 177 | progress => { 178 | const increment = 100 / mechanisms.length; 179 | let current = 0; 180 | 181 | progress.report({ increment: 0 }); 182 | 183 | return Promise.all(mechanisms.map(async mechanism => { 184 | AttributionMechanismService.saveFile( 185 | mechanism.attributionMecanismPK.attributionMecanismId, 186 | mechanism.attributionMecanismDescription, 187 | false 188 | ); 189 | current += increment; 190 | progress.report({ increment: current }); 191 | return true; 192 | })); 193 | } 194 | ); 195 | 196 | window.showInformationMessage(`${results.length} Mecanismos Customizados foram importados.`); 197 | } 198 | 199 | /** 200 | * Cria ou Atualiza Mecanismo de Atribuição no servidor 201 | */ 202 | public static async export(fileUri: Uri) { 203 | const server = await ServerService.getSelect(); 204 | 205 | if (!server) { 206 | return; 207 | } 208 | 209 | const mechanisms = await AttributionMechanismService.list(server); 210 | const items = []; 211 | 212 | let mechanismSelected = { label: "", detail: "" }; 213 | let mechanismId: string = basename(fileUri.fsPath, '.js'); 214 | 215 | for (let mechanism of mechanisms) { 216 | if (mechanism.attributionMecanismPK.attributionMecanismId !== mechanismId) { 217 | items.push({ label: mechanism.attributionMecanismPK.attributionMecanismId, detail: mechanism.name }); 218 | } else { 219 | mechanismSelected = { label: mechanism.attributionMecanismPK.attributionMecanismId, detail: mechanism.name }; 220 | } 221 | } 222 | 223 | items.unshift({ label: 'Novo Mecanismo Customizado', detail: "" }); 224 | 225 | if (mechanismSelected.label !== '') { 226 | items.unshift(mechanismSelected); 227 | } 228 | 229 | mechanismSelected = (await window.showQuickPick(items, { 230 | placeHolder: "Criar ou Editar Mecanismo Customizado?" 231 | })) || { label: "", detail: "" }; 232 | 233 | if (!mechanismSelected.label) { 234 | return; 235 | } 236 | 237 | const isNew = mechanismSelected.label === 'Novo Mecanismo Customizado'; 238 | 239 | let mechanismStructure: AttributionMechanismDTO | undefined = undefined; 240 | let name: string = ''; 241 | let description: string = ''; 242 | 243 | if (isNew) { 244 | let existMechanism: boolean = false; 245 | 246 | do { 247 | mechanismId = await window.showInputBox({ 248 | prompt: "Qual o código do Mecanismo Customizado (sem espaços e sem caracteres especiais)?", 249 | placeHolder: "mecanismo_customizado", 250 | value: mechanismId 251 | }) || ""; 252 | 253 | if (!mechanismId) { 254 | return; 255 | } 256 | 257 | existMechanism = mechanisms.find((mechanism => mechanism.attributionMecanismPK.attributionMecanismId === mechanismId)) !== undefined; 258 | 259 | if (existMechanism) { 260 | window.showWarningMessage(`O mecanismo "${mechanismId}" já existe no servidor "${server.name}"!`); 261 | } 262 | } while (existMechanism); 263 | 264 | mechanismStructure = { 265 | attributionMecanismPK: { 266 | companyId: server.companyId, 267 | attributionMecanismId: mechanismId 268 | }, 269 | assignmentType: 1, 270 | controlClass: "com.datasul.technology.webdesk.workflow.assignment.customization.CustomAssignmentImpl", 271 | preSelectionClass: null, 272 | configurationClass: "", 273 | name: "", 274 | description: "", 275 | attributionMecanismDescription: "" 276 | }; 277 | } else { 278 | mechanismId = mechanismSelected.label; 279 | mechanismStructure = mechanisms.find(mechanism => mechanism.attributionMecanismPK.attributionMecanismId === mechanismId); 280 | } 281 | 282 | name = await window.showInputBox({ 283 | prompt: "Qual o nome do Mecanismo Customizado?", 284 | placeHolder: "Nome do Mecanismo", 285 | value: mechanismStructure?.name || mechanismId 286 | }) || ""; 287 | 288 | description = await window.showInputBox({ 289 | prompt: "Qual a descrição do Mecanismo Customizado?", 290 | placeHolder: "Descrição do Mecanismo", 291 | value: mechanismStructure?.description || mechanismId 292 | }) || ""; 293 | 294 | if (!mechanismStructure || !description || !name) { 295 | return; 296 | } 297 | 298 | mechanismStructure.name = name; 299 | mechanismStructure.description = description; 300 | mechanismStructure.attributionMecanismDescription = readFileSync(fileUri.fsPath, 'utf8'); 301 | 302 | let result: any = undefined; 303 | 304 | // Validar senha antes de exportar 305 | if (server.confirmExporting && !(await UtilsService.confirmPassword(server))) { 306 | return; 307 | } 308 | 309 | if (isNew) { 310 | result = await AttributionMechanismService.create(server, mechanismStructure); 311 | } else { 312 | result = await AttributionMechanismService.update(server, mechanismStructure); 313 | } 314 | 315 | if (result.content === 'OK') { 316 | window.showInformationMessage(`Mecanismo Customizado ${mechanismId} exportado com sucesso!`); 317 | } else { 318 | window.showErrorMessage(`Falha ao exportar o Mecanismo Customizado ${mechanismId}!\n${result.message.message}`); 319 | } 320 | } 321 | 322 | /** 323 | * Cria o arquivo de Mecanismo de Atribuição 324 | */ 325 | private static async saveFile(name: string, content: string, openFile: boolean = true) { 326 | const fileUri = Uri.joinPath(UtilsService.getWorkspaceUri(), "mechanisms", name + ".js"); 327 | 328 | await workspace.fs.writeFile( 329 | fileUri, 330 | Buffer.from(content, "utf-8") 331 | ); 332 | 333 | if (openFile) { 334 | window.showTextDocument(fileUri); 335 | window.showInformationMessage(`Mecanismo de Atribuição ${name} importado com sucesso!`); 336 | } 337 | } 338 | } 339 | -------------------------------------------------------------------------------- /resources/views/dataset/dataset.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | const vscode = acquireVsCodeApi(); 3 | 4 | const FIELDS_TO_SELECT = "#fieldsToSelect"; 5 | const FIELDS_SELECTED = "#fieldsSelected"; 6 | 7 | const FIELDS_TO_ORDER = "#fieldsToOrder"; 8 | const FIELDS_ORDERED = "#fieldsOrdered"; 9 | 10 | const MODAL = $("#modalConfigFiltro"); 11 | 12 | let dataTable = null; 13 | let currentDataset = ""; 14 | 15 | let needLoadFields = true; 16 | let needResetConstraints = true; 17 | 18 | let $loading = null; 19 | let $constraints = null; 20 | let constraintsFields = []; 21 | 22 | $(function () { 23 | $loading = $("#loading").modal({ 24 | backdrop: "static", 25 | keyboard: false, 26 | focus: false 27 | }).modal("show"); 28 | 29 | $("#consultarDataset").on("click", getResultQuery); 30 | $("#atualizaConsulta").on("click", getResultQuery); 31 | $("#addConstraint").on("click", () => addConstraints(false)); 32 | 33 | $("#constraints").on("click", ".removeConstraint", removeConstraints); 34 | 35 | $constraints = $("#constraints"); 36 | 37 | sortable(FIELDS_TO_SELECT, { 38 | acceptFrom: FIELDS_TO_SELECT + "," + FIELDS_SELECTED, 39 | hoverClass: "sortable-hover", 40 | }); 41 | 42 | sortable(FIELDS_SELECTED, { 43 | acceptFrom: FIELDS_TO_SELECT + "," + FIELDS_SELECTED, 44 | hoverClass: "sortable-hover", 45 | itemSerializer: fieldsSelectedSerializer, 46 | }); 47 | 48 | sortable(FIELDS_TO_ORDER, { 49 | acceptFrom: FIELDS_TO_ORDER + "," + FIELDS_ORDERED, 50 | hoverClass: "sortable-hover", 51 | }); 52 | 53 | sortable(FIELDS_ORDERED, { 54 | acceptFrom: FIELDS_TO_ORDER + "," + FIELDS_ORDERED, 55 | hoverClass: "sortable-hover", 56 | maxItems: 2, 57 | itemSerializer: fieldsOrderedSerializer, 58 | }); 59 | 60 | vscode.postMessage({ 61 | command: 'load_datasets' 62 | }); 63 | }); 64 | 65 | window.addEventListener('message', event => { 66 | const message = event.data; 67 | 68 | switch (message.command) { 69 | case 'load_datasets': 70 | $("#dataset").select2({ 71 | placeholder: "Selecione o Dataset", 72 | data: message.datasets 73 | }); 74 | hideLoading(); 75 | break; 76 | 77 | case 'query_result': 78 | const queryResult = message.queryResult 79 | 80 | if (needLoadFields) { 81 | setFields(queryResult); 82 | } 83 | 84 | if (needResetConstraints) { 85 | addConstraints(true); 86 | } 87 | 88 | updateTableResult(queryResult); 89 | hideLoading(); 90 | break; 91 | 92 | case 'error': 93 | hideLoading(); 94 | break; 95 | } 96 | }); 97 | 98 | function updateTableResult(queryResult) { 99 | const {columns, values} = queryResult; 100 | 101 | const tbResult = document.getElementById('tbResultDataset'); 102 | const $tbResult = $(tbResult); 103 | 104 | if (dataTable) { 105 | dataTable.destroy(); 106 | $tbResult.empty(); 107 | dataTable = null; 108 | } 109 | 110 | tbResult.innerHTML = ""; 111 | 112 | // Montando cabeçalho da tabela 113 | const header = tbResult.createTHead(); 114 | const title = header.insertRow(); 115 | 116 | for (let columnName of columns) { 117 | const column = document.createElement('th'); 118 | column.innerHTML = columnName; 119 | title.appendChild(column); 120 | } 121 | 122 | // Listando os registros 123 | const records = tbResult.appendChild(document.createElement('tbody')); 124 | 125 | for(let value of values) { 126 | const row = records.insertRow(); 127 | 128 | for(let columnName of columns) { 129 | row.insertCell().innerHTML = value[columnName]; 130 | } 131 | } 132 | 133 | tbResult.appendChild(records); 134 | 135 | dataTable = $tbResult.DataTable({ 136 | order: [], 137 | fixedHeader: true, 138 | scrollX: true, 139 | layout: { 140 | topStart: 'pageLength', 141 | topEnd: 'search', 142 | bottomStart: 'info', 143 | bottomEnd: 'paging', 144 | bottom2Start: { 145 | buttons: [ 146 | { 147 | extend: 'copyHtml5', 148 | text: "Copiar", 149 | title: null, 150 | header: true, 151 | footer: false, 152 | }, 153 | { 154 | extend: 'excelHtml5', 155 | text: "Exportar Excel", 156 | filename() { 157 | return getExcelName(); 158 | }, 159 | title() { 160 | return getExcelName(); 161 | }, 162 | }, 163 | ], 164 | }, 165 | } 166 | }); 167 | } 168 | 169 | function getExcelName() { 170 | return serverName + ' - ' + document.getElementById("dataset").value; 171 | } 172 | 173 | function getResultQuery() { 174 | const dataset = document.getElementById("dataset").value; 175 | 176 | if (!dataset) { 177 | return; 178 | } 179 | 180 | showLoading(); 181 | 182 | if (currentDataset == "") { 183 | currentDataset = dataset; 184 | const constraints = getConstraints(); 185 | needLoadFields = true; 186 | needResetConstraints = !constraints.length; 187 | 188 | vscode.postMessage({ 189 | command: 'consult_dataset', 190 | datasetId: dataset, 191 | fields: [], 192 | constraints: constraints.length ? constraints : getConstraints(true), 193 | order: [] 194 | }); 195 | 196 | return; 197 | } 198 | 199 | if (currentDataset != dataset) { 200 | currentDataset = dataset; 201 | needLoadFields = true; 202 | needResetConstraints = true; 203 | $constraints.empty(); 204 | resetFieldsSelect(); 205 | 206 | vscode.postMessage({ 207 | command: 'consult_dataset', 208 | datasetId: dataset, 209 | fields: getFields(), 210 | constraints: getConstraints(true), 211 | order: getOrders() 212 | }); 213 | 214 | return; 215 | } 216 | 217 | needLoadFields = false; 218 | needResetConstraints = false; 219 | 220 | vscode.postMessage({ 221 | command: 'consult_dataset', 222 | datasetId: dataset, 223 | fields: getFields(), 224 | constraints: getConstraints(), 225 | order: getOrders() 226 | }); 227 | } 228 | 229 | function resetFieldsSelect() { 230 | $(FIELDS_TO_SELECT).empty(); 231 | $(FIELDS_SELECTED).empty(); 232 | $(FIELDS_TO_ORDER).empty(); 233 | $(FIELDS_ORDERED).empty(); 234 | } 235 | 236 | function reloadFieldsSelectSortable() { 237 | sortable(FIELDS_TO_SELECT); 238 | sortable(FIELDS_SELECTED); 239 | sortable(FIELDS_TO_ORDER); 240 | sortable(FIELDS_ORDERED); 241 | } 242 | 243 | function removeConstraints(ev) { 244 | ev.preventDefault(); 245 | this.parentElement.parentElement.remove(); 246 | } 247 | 248 | function addConstraints(isReset) { 249 | isReset = isReset || false; 250 | 251 | let constraint = $( 252 | '' 253 | + '' 254 | + '' 255 | + '' 256 | + '' 257 | + '' 258 | + '' 259 | + '' 260 | + '' 265 | + '' 266 | + '' 267 | + '' 271 | + '' 272 | + 'X' 273 | + '' 274 | ); 275 | 276 | const select = constraint.find('select:first'); 277 | 278 | select.select2({ 279 | placeholder: "Selecione o Campo", 280 | data: constraintsFields, 281 | tags: true, 282 | dropdownParent: MODAL, 283 | }); 284 | 285 | if (isReset) { 286 | select.val("sqlLimit").trigger("change"); 287 | } 288 | 289 | $constraints.append(constraint); 290 | } 291 | 292 | function getConstraints(resetItems) { 293 | resetItems = resetItems || false; 294 | 295 | // Limpa constraints para evitar erros 296 | if (resetItems) { 297 | return [{ 298 | fieldName: "sqlLimit", 299 | initialValue: "100", 300 | finalValue: "100", 301 | contraintType: "MUST", 302 | likeSearch: "false" 303 | }]; 304 | } 305 | 306 | const rows = $constraints.find("tr"); 307 | const datasetConstraints = []; 308 | 309 | for (let row of rows) { 310 | const fields = $(row).find(".form-control"); 311 | 312 | datasetConstraints.push({ 313 | fieldName: fields[0].value, 314 | initialValue: fields[1].value, 315 | finalValue: fields[2].value, 316 | contraintType: fields[3].value, 317 | likeSearch: fields[4].value 318 | }); 319 | } 320 | 321 | return datasetConstraints; 322 | } 323 | 324 | function getFields() { 325 | let items = sortable(FIELDS_SELECTED, "serialize")[0].items; 326 | return items.map(item => item.field); 327 | } 328 | 329 | function getOrders() { 330 | let items = sortable(FIELDS_ORDERED, "serialize")[0].items; 331 | return items.map(item => item.field); 332 | } 333 | 334 | function setFields(queryResult) { 335 | const {columns} = queryResult; 336 | 337 | constraintsFields = []; 338 | let fieldsToSelect = []; 339 | let fieldsToOrder = []; 340 | 341 | for (let optionName of columns) { 342 | constraintsFields.push({ 343 | id: optionName, 344 | text: optionName 345 | }); 346 | fieldsToSelect.push("
  • "+ optionName + "
  • "); 347 | fieldsToOrder.push('
  • ' 348 | + '' 349 | + '' 350 | + '
  • ' 351 | ); 352 | } 353 | 354 | constraintsFields.push({id: "sqlLimit", text: "sqlLimit"}); 355 | constraintsFields.push({id: "tablename", text: "tablename"}); 356 | 357 | $(FIELDS_TO_SELECT).append(fieldsToSelect); 358 | $(FIELDS_TO_ORDER).append(fieldsToOrder); 359 | 360 | reloadFieldsSelectSortable(); 361 | } 362 | 363 | function fieldsSelectedSerializer(serializedItem, sortableContainer) { 364 | return { 365 | field: serializedItem.html.replace(/<[^>]+>([^>]+)<.*>/, '$1'), 366 | } 367 | } 368 | 369 | function fieldsOrderedSerializer(serializedItem, sortableContainer) { 370 | let field = serializedItem.html.replace(/.*]+>([^>]+)<.*>.*/, '$1'); 371 | let checkbox = document.getElementById(field); 372 | 373 | if (checkbox && checkbox.checked) { 374 | field += ";desc"; 375 | } 376 | 377 | return { 378 | field, 379 | } 380 | } 381 | 382 | function showLoading() { 383 | $loading.modal("show"); 384 | } 385 | 386 | function hideLoading() { 387 | $loading.modal("hide"); 388 | 389 | // Força fechamento da modal 390 | setTimeout( 391 | function () { 392 | if ($loading.hasClass("show")) { 393 | $loading.modal("hide"); 394 | } 395 | }, 396 | 500 397 | ); 398 | } 399 | }()); 400 | --------------------------------------------------------------------------------