├── .env ├── .gitignore ├── AUTHORS ├── LICENSE.md ├── README.md ├── babel.config.js ├── package-lock.json ├── package.json ├── public ├── favicon.ico └── index.html ├── screenshot.png ├── src ├── App.vue ├── assets │ ├── images │ │ └── MoquiLogoNew.png │ ├── js │ │ └── main.js │ ├── logo.png │ └── scss │ │ ├── _demo.scss │ │ ├── _fonts.scss │ │ ├── _footer.scss │ │ ├── _functions.scss │ │ ├── _misc.scss │ │ ├── _navbar.scss │ │ ├── _reset.scss │ │ ├── _sidebar.scss │ │ ├── _typography.scss │ │ ├── _utilities.scss │ │ ├── _variables.scss │ │ ├── components │ │ ├── _badges.scss │ │ ├── _bootstrap-progress.scss │ │ ├── _breadcrumbs.scss │ │ ├── _buttons.scss │ │ ├── _cards.scss │ │ ├── _carousel.scss │ │ ├── _checkbox-radio.scss │ │ ├── _dropdown.scss │ │ ├── _forms.scss │ │ ├── _icons.scss │ │ ├── _pagination.scss │ │ ├── _preview.scss │ │ ├── _tables.scss │ │ └── _tabs.scss │ │ ├── custom │ │ └── custom.scss │ │ ├── dashboard.scss │ │ ├── landing-screens │ │ ├── _auth.scss │ │ └── _error.scss │ │ ├── mixins │ │ ├── _animation.scss │ │ ├── _background.scss │ │ ├── _badges.scss │ │ ├── _blockqoute.scss │ │ ├── _breadcrumbs.scss │ │ ├── _buttons.scss │ │ ├── _cards.scss │ │ ├── _misc.scss │ │ ├── _pagination.scss │ │ ├── _tabs.scss │ │ └── _text.scss │ │ └── style.scss ├── components │ ├── guest │ │ ├── error │ │ │ ├── Error403.vue │ │ │ └── Error404.vue │ │ └── login │ │ │ └── Login.vue │ ├── secure │ │ ├── status-flow │ │ │ ├── StatusFlowLookup.vue │ │ │ └── StatusFlowModal.vue │ │ ├── user-group │ │ │ ├── UserGroupLookup.vue │ │ │ └── UserGroupModal.vue │ │ ├── user │ │ │ ├── UserLookup.vue │ │ │ └── UserModal.vue │ │ ├── workflow-props │ │ │ ├── AdjustmentActivityProps.vue │ │ │ ├── ConditionActivityProps.vue │ │ │ ├── ExitActivityProps.vue │ │ │ ├── NotificationActivityProps.vue │ │ │ ├── ServiceActivityProps.vue │ │ │ └── UserActivityProps.vue │ │ ├── workflow-task │ │ │ ├── WorkflowTask.vue │ │ │ ├── WorkflowTaskBrowse.vue │ │ │ └── WorkflowTaskView.vue │ │ └── workflow │ │ │ ├── Workflow.vue │ │ │ ├── WorkflowBrowse.vue │ │ │ ├── WorkflowCreate.vue │ │ │ ├── WorkflowDesigner.vue │ │ │ ├── WorkflowLookup.vue │ │ │ ├── WorkflowModal.vue │ │ │ ├── WorkflowModify.vue │ │ │ ├── WorkflowPreview.vue │ │ │ └── WorkflowView.vue │ └── theme │ │ ├── fragments │ │ ├── AppFooter.vue │ │ ├── AppHeader.vue │ │ ├── AppSidebar.vue │ │ └── common │ │ │ └── Breadcrumb.vue │ │ └── layouts │ │ ├── Full.vue │ │ └── Main.vue ├── filters │ ├── FormatUnixDate.js │ ├── FormatUnixTimestamp.js │ ├── FromNow.js │ ├── PrettyBool.js │ ├── PrettyNull.js │ └── index.js ├── main.js ├── mixins │ ├── AlertMixin.js │ ├── AutoCompleteMixin.js │ ├── DisabledClassMixin.js │ ├── PagingTableMixin.js │ ├── StatusFlowTableMixin.js │ ├── StatusItemTableMixin.js │ ├── UserGroupTableMixin.js │ ├── UserTableMixin.js │ ├── WorkflowCrowdProcessMixin.js │ ├── WorkflowProcessMixin.js │ ├── WorkflowTableMixin.js │ ├── WorkflowTaskTableMixin.js │ └── WorkflowTimeoutProcessMixin.js ├── navigation │ └── MainMenu.js ├── router.js ├── services │ ├── EntityFieldService.js │ ├── EnumService.js │ ├── PublicEndpoint.js │ ├── SecureEndpoint.js │ ├── SecurityService.js │ ├── StatusFlowService.js │ ├── UomService.js │ ├── WorkflowService.js │ └── WorkflowTypeService.js ├── shapes │ ├── AdjustmentActivity.js │ ├── ConditionActivity.js │ ├── EnterActivity.js │ ├── ExitActivity.js │ ├── NotificationActivity.js │ ├── ServiceActivity.js │ └── UserActivity.js └── store.js ├── tests ├── e2e │ ├── custom-assertions │ │ └── elementCount.js │ └── specs │ │ └── test.js └── unit │ ├── .eslintrc.js │ └── example.spec.js └── vue.config.js /.env: -------------------------------------------------------------------------------- 1 | VUE_APP_ID = WORKFLOW-BUILDER 2 | VUE_APP_API_BASE_PATH = /rest/s1 3 | VUE_APP_PRODUCTION_PATH = /web/ 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | /tests/e2e/reports/ 6 | selenium-debug.log 7 | 8 | # local env files 9 | .env.local 10 | .env.*.local 11 | 12 | # Log files 13 | npm-debug.log* 14 | yarn-debug.log* 15 | yarn-error.log* 16 | 17 | # Editor directories and files 18 | .idea 19 | .vscode 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw* 25 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Moqui Workflow Engine (https://github.com/Netvariant/moqui-workflow) 2 | 3 | This software is in the public domain under CC0 1.0 Universal plus a 4 | Grant of Patent License. 5 | 6 | To the extent possible under law, the author(s) have dedicated all 7 | copyright and related and neighboring rights to this software to the 8 | public domain worldwide. This software is distributed without any 9 | warranty. 10 | 11 | You should have received a copy of the CC0 Public Domain Dedication 12 | along with this software (see the LICENSE.md file). If not, see 13 | . 14 | 15 | =========================================================================== 16 | 17 | Copyright Waiver 18 | 19 | I dedicate any and all copyright interest in this software to the 20 | public domain. I make this dedication for the benefit of the public at 21 | large and to the detriment of my heirs and successors. I intend this 22 | dedication to be an overt act of relinquishment in perpetuity of all 23 | present and future rights to this software under copyright law. 24 | 25 | To the best of my knowledge and belief, my contributions are either 26 | originally authored by me or are derived from prior works which I have 27 | verified are also in the public domain and are not subject to claims 28 | of copyright by other parties. 29 | 30 | To the best of my knowledge and belief, no individual, business, 31 | organization, government, or other entity has any copyright interest 32 | in my contributions, and I affirm that I will not make contributions 33 | that are otherwise encumbered. 34 | 35 | Signed by git commit adding my legal name and git username: 36 | 37 | Written in 2019 by Ayman Abi Abdallah - aabiabdallah 38 | Written in 2019 by Mazen Khowise - mkhowise 39 | 40 | =========================================================================== 41 | 42 | Grant of Patent License 43 | 44 | I hereby grant to recipients of software a perpetual, worldwide, 45 | non-exclusive, no-charge, royalty-free, irrevocable (except as stated in 46 | this section) patent license to make, have made, use, offer to sell, sell, 47 | import, and otherwise transfer the Work, where such license applies only to 48 | those patent claims licensable by me that are necessarily infringed by my 49 | Contribution(s) alone or by combination of my Contribution(s) with the 50 | Work to which such Contribution(s) was submitted. If any entity institutes 51 | patent litigation against me or any other entity (including a cross-claim 52 | or counterclaim in a lawsuit) alleging that my Contribution, or the Work to 53 | which I have contributed, constitutes direct or contributory patent 54 | infringement, then any patent licenses granted to that entity under this 55 | Agreement for that Contribution or Work shall terminate as of the date such 56 | litigation is filed. 57 | 58 | Signed by git commit adding my legal name and git username: 59 | 60 | Written in 2019 by Ayman Abi Abdallah - aabiabdallah 61 | Written in 2019 by Mazen Khowise - mkhowise 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Workflow Designer 2 | 3 | Standalone Moqui workflow designer application based on Vue.js. 4 | 5 | ![](screenshot.png) 6 | 7 | ## Table of Contents 8 | 9 | - [Installation](#installation) 10 | - [Configuration](#configuration) 11 | - [Authors](#authors) 12 | - [License](#license) 13 | 14 | ## Installation 15 | 16 | You will be carrying out these steps to install the workflow designer. 17 | 18 | * Download the workflow designer 19 | * Install dependencies & run workflow designer 20 | 21 | ### Download the workflow designer 22 | 23 | Clone the workflow designer repository using this command: 24 | 25 | ```shell 26 | $ git clone https://github.com/Netvariant/workflow-designer.git 27 | ``` 28 | 29 | ### Install dependencies & run workflow designer 30 | 31 | The workflow designer uses NPM for dependency management. Install dependencies and run the workflow designer using these commands: 32 | 33 | ```shell 34 | $ npm install 35 | $ npm run serve 36 | ``` 37 | 38 | You can also build the project for production use using this command: 39 | 40 | ```shell 41 | $ npm run build 42 | ``` 43 | 44 | > Remember, the user account you use to login must be a member of a group that has access to the `Moqui Workflow REST API` artifact group. 45 | 46 | ## Configuration 47 | 48 | The workflow designer communicates with your Moqui instance using REST APIs. 49 | The base API URL path is configured in the `.env` file. 50 | All API requests are pass though a proxy to reach the Moqui instance, this is configured in the `vue.config.js` file. 51 | 52 | ```javascript 53 | module.exports = { 54 | // ... 55 | proxy: { 56 | // proxy all requests starting with /rest/s1 to localhost:8080 57 | '/rest/s1': { 58 | target: 'http://localhost:8080', 59 | ws: true, 60 | changeOrigin: true 61 | } 62 | } 63 | // ... 64 | } 65 | ``` 66 | 67 | See the [Configuration Reference](https://cli.vuejs.org/config/) for a detailed description of all available configuration options. 68 | 69 | ## Authors 70 | 71 | This project was build with :heart: by the good fellas at [Netvariant](https://www.netvariant.com). 72 | 73 | ## License 74 | 75 | [![license](http://img.shields.io/badge/license-CC0%201.0%20Universal-blue.svg)](https://github.com/Netvariant/moqui-workflow/blob/master/LICENSE.md) 76 | 77 | This project is licensed under the CC0 License, see the [LICENSE.md](LICENSE.md) file for details. 78 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "workflow", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint", 9 | "test:e2e": "vue-cli-service test:e2e", 10 | "test:unit": "vue-cli-service test:unit" 11 | }, 12 | "dependencies": { 13 | "@fortawesome/fontawesome-free": "^5.8.1", 14 | "@mdi/font": "^3.5.95", 15 | "axios": "^0.18.0", 16 | "bootstrap": "^4.3.1", 17 | "bootstrap-vue": "^2.0.0-rc.15", 18 | "compass-mixins": "^0.12.10", 19 | "core-js": "^2.6.5", 20 | "css-loader": "^2.1.1", 21 | "draw2d": "^1.0.18", 22 | "flag-icon-css": "^3.3.0", 23 | "font-awesome": "^4.7.0", 24 | "jquery": "^3.3.1", 25 | "jquery-ui": "^1.12.1", 26 | "moment": "^2.24.0", 27 | "nprogress": "^0.2.0", 28 | "popper.js": "^1.14.7", 29 | "vue": "^2.6.6", 30 | "vue-codemirror": "^4.0.6", 31 | "vue-router": "^3.0.1", 32 | "vue-simple-suggest": "^1.8.3", 33 | "vuex": "^3.0.1", 34 | "vuex-i18n": "^1.11.0" 35 | }, 36 | "devDependencies": { 37 | "@vue/cli-plugin-babel": "^3.5.0", 38 | "@vue/cli-plugin-eslint": "^3.5.0", 39 | "@vue/cli-plugin-unit-jest": "^3.5.0", 40 | "@vue/cli-service": "^3.5.0", 41 | "@vue/eslint-config-standard": "^4.0.0", 42 | "@vue/test-utils": "1.0.0-beta.29", 43 | "babel-core": "7.0.0-bridge.0", 44 | "babel-eslint": "^10.0.1", 45 | "babel-jest": "^23.6.0", 46 | "eslint": "^5.8.0", 47 | "eslint-plugin-vue": "^5.0.0", 48 | "node-sass": "^4.9.0", 49 | "sass-loader": "^7.1.0", 50 | "vue-template-compiler": "^2.5.21" 51 | }, 52 | "eslintConfig": { 53 | "root": true, 54 | "env": { 55 | "node": true 56 | }, 57 | "extends": [ 58 | "plugin:vue/essential", 59 | "@vue/standard" 60 | ], 61 | "rules": {}, 62 | "parserOptions": { 63 | "parser": "babel-eslint" 64 | } 65 | }, 66 | "postcss": { 67 | "plugins": { 68 | "autoprefixer": {} 69 | } 70 | }, 71 | "browserslist": [ 72 | "> 1%", 73 | "last 2 versions", 74 | "not ie <= 8" 75 | ], 76 | "jest": { 77 | "moduleFileExtensions": [ 78 | "js", 79 | "jsx", 80 | "json", 81 | "vue" 82 | ], 83 | "transform": { 84 | "^.+\\.vue$": "vue-jest", 85 | ".+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$": "jest-transform-stub", 86 | "^.+\\.jsx?$": "babel-jest" 87 | }, 88 | "transformIgnorePatterns": [ 89 | "/node_modules/" 90 | ], 91 | "moduleNameMapper": { 92 | "^@/(.*)$": "/src/$1" 93 | }, 94 | "snapshotSerializers": [ 95 | "jest-serializer-vue" 96 | ], 97 | "testMatch": [ 98 | "**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)" 99 | ], 100 | "testURL": "http://localhost/" 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netvariant/workflow-designer/78cdff621f4d56ec6fdee9d8e19c3247d500afb2/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Moqui Workflow Designer 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netvariant/workflow-designer/78cdff621f4d56ec6fdee9d8e19c3247d500afb2/screenshot.png -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/assets/images/MoquiLogoNew.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netvariant/workflow-designer/78cdff621f4d56ec6fdee9d8e19c3247d500afb2/src/assets/images/MoquiLogoNew.png -------------------------------------------------------------------------------- /src/assets/js/main.js: -------------------------------------------------------------------------------- 1 | /* 2 | Main javascript functions to init most of the elements 3 | #1. FORM STEPS FUNCTIONALITY 4 | */ 5 | 6 | import $ from 'jquery' 7 | // Launch full Screen 8 | function launchIntoFullscreen (element) { 9 | if (element.requestFullscreen) { 10 | element.requestFullscreen() 11 | } else if (element.mozRequestFullScreen) { 12 | element.mozRequestFullScreen() 13 | } else if (element.webkitRequestFullscreen) { 14 | element.webkitRequestFullscreen() 15 | } else if (element.msRequestFullscreen) { 16 | element.msRequestFullscreen() 17 | } 18 | } 19 | // Exit fullscreen 20 | function exitFullscreen () { 21 | if (document.exitFullscreen) { 22 | document.exitFullscreen() 23 | } else if (document.mozCancelFullScreen) { 24 | document.mozCancelFullScreen() 25 | } else if (document.webkitExitFullscreen) { 26 | document.webkitExitFullscreen() 27 | } 28 | } 29 | export default { 30 | form_steps_trigger_v2 () { 31 | // #7. FORM STEPS FUNCTIONALITY 32 | $('.step-trigger-btn').on('click', function () { 33 | var btnHref = $(this).attr('href') 34 | $('.step-trigger[href="' + btnHref + '"]').click() 35 | return false 36 | }) 37 | 38 | // FORM STEP CLICK 39 | $('.step-trigger').on('click', function () { 40 | var prevTrigger = $(this).prev('.step-trigger') 41 | if (prevTrigger.length && !prevTrigger.hasClass('active') && !prevTrigger.hasClass('complete')) return false 42 | var contentId = $(this).attr('href') 43 | $(this).closest('.step-triggers').find('.step-trigger').removeClass('active') 44 | $(this).prev('.step-trigger').addClass('complete') 45 | $(this).addClass('active') 46 | $('.step-content').removeClass('active') 47 | $('.step-content' + contentId).addClass('active') 48 | return false 49 | }) 50 | // END STEPS FUNCTIONALITY 51 | }, 52 | toggle_full_screen (elementId) { 53 | var docElm = document.documentElement 54 | if ($('body').hasClass('window-full-screen')) { 55 | exitFullscreen() 56 | $(elementId).removeClass('element-full-screen-mode') 57 | $('#sidebar').show() 58 | } else { 59 | launchIntoFullscreen(docElm) 60 | $(elementId).addClass('element-full-screen-mode') 61 | $('#sidebar').hide() 62 | } 63 | return false 64 | }, 65 | full_screen_toggler () { 66 | // Full Screen Toggler 67 | $('.full-screen-toggle').on('click', function () { 68 | var docElm = document.documentElement 69 | if ($('body').hasClass('window-full-screen')) { 70 | exitFullscreen() 71 | } else { 72 | launchIntoFullscreen(docElm) 73 | } 74 | return false 75 | }) 76 | }, 77 | full_screen () { 78 | $(document).bind('webkitfullscreenchange mozfullscreenchange fullscreenchange', function (e) { 79 | var state = document.fullScreen || document.mozFullScreen || document.webkitIsFullScreen 80 | if (state) { 81 | $('body').addClass('window-full-screen') 82 | } else { 83 | $('body').removeClass('window-full-screen') 84 | $('#sidebar').show() 85 | } 86 | }) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netvariant/workflow-designer/78cdff621f4d56ec6fdee9d8e19c3247d500afb2/src/assets/logo.png -------------------------------------------------------------------------------- /src/assets/scss/_demo.scss: -------------------------------------------------------------------------------- 1 | /* Demo Styles */ 2 | // Add spacing to Boostrap components for demo purpose 3 | 4 | .template-demo { 5 | > .btn { 6 | @extend .mt-2; 7 | @extend .mr-2; 8 | } 9 | 10 | > .btn-toolbar { 11 | @extend .mt-2; 12 | @extend .mr-2; 13 | } 14 | 15 | > .btn-group { 16 | @extend .mt-2; 17 | @extend .mr-2; 18 | 19 | .btn { 20 | margin: 0 !important; 21 | } 22 | } 23 | 24 | > h1, 25 | > h3, 26 | > h4, 27 | > h5, 28 | > h6, 29 | > h2 { 30 | border-top: 1px solid $border-color; 31 | padding: 0.5rem 0 0; 32 | } 33 | 34 | .dropdown { 35 | display: inline-block; 36 | @extend .mr-2; 37 | margin-bottom: 0.5rem; 38 | } 39 | 40 | nav { 41 | .breadcrumb { 42 | margin-bottom: 1.375rem; 43 | } 44 | 45 | &:last-child { 46 | .breadcrumb { 47 | margin-bottom: 0; 48 | } 49 | } 50 | } 51 | > .progress { 52 | margin-bottom: 15px; 53 | } 54 | } 55 | 56 | .purchace-popup { 57 | > div { 58 | @extend .grid-margin; 59 | 60 | > span { 61 | background: rgba(228, 228, 228, 0.46); 62 | padding: 15px 20px; 63 | @include border-radius(3px); 64 | 65 | .btn { 66 | margin-right: 20px; 67 | font-weight: 500; 68 | color: $white; 69 | @include border-radius(5px); 70 | &.download-button{ 71 | background: rgba(#e4e4e4,0.2); 72 | color: darken(#e4e4e4,20%); 73 | border:2px solid darken(#e4e4e4,10%); 74 | } 75 | &.purchase-button{ 76 | background-color: #d209fa; 77 | @include filter-gradient(#d209fa, #4f81d4, horizontal); 78 | @include background-image(linear-gradient(to right, #d209fa 1%,#4f81d4 100%)); 79 | color: $white; 80 | border: none; 81 | line-height: 1; 82 | vertical-align: middle; 83 | } 84 | } 85 | 86 | p { 87 | margin-bottom: auto; 88 | margin-top: auto; 89 | color: darken(#e4e4e4,40%); 90 | font-weight: 400; 91 | vertical-align: middle; 92 | line-height: 1; 93 | } 94 | 95 | i { 96 | vertical-align: middle; 97 | line-height: 1; 98 | margin: auto 0; 99 | color: darken(#e4e4e4,20%); 100 | } 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/assets/scss/_fonts.scss: -------------------------------------------------------------------------------- 1 | /* Fonts */ 2 | 3 | @import url('https://fonts.googleapis.com/css?family=Poppins:400,500,600'); -------------------------------------------------------------------------------- /src/assets/scss/_footer.scss: -------------------------------------------------------------------------------- 1 | /* Footer */ 2 | 3 | 4 | .footer { 5 | background: $footer-bg; 6 | color: $footer-color; 7 | padding: 20px 1rem; 8 | transition: all $action-transition-duration $action-transition-timing-function; 9 | -moz-transition: all $action-transition-duration $action-transition-timing-function; 10 | -webkit-transition: all $action-transition-duration $action-transition-timing-function; 11 | -ms-transition: all $action-transition-duration $action-transition-timing-function; 12 | border-top: $border-width solid $border-color; 13 | font-size: calc(#{$default-font-size} - 0.05rem); 14 | font-family: $type-1; 15 | 16 | a { 17 | color: theme-color(success); 18 | font-size: inherit; 19 | } 20 | @media (max-width: 991px) { 21 | margin-left: 0; 22 | width: 100%; 23 | } 24 | } -------------------------------------------------------------------------------- /src/assets/scss/_functions.scss: -------------------------------------------------------------------------------- 1 | // Functions 2 | 3 | @function social-color($key: "twitter") { 4 | @return map-get($social-colors, $key); 5 | } 6 | 7 | // Social Color 8 | @each $color, $value in $social-colors { 9 | .text-#{$color} { 10 | @include text-color(social-color($color)); 11 | } 12 | } 13 | 14 | @each $color, $value in $social-colors { 15 | .bg-#{$color} { 16 | background: social-color($color); 17 | } 18 | } -------------------------------------------------------------------------------- /src/assets/scss/_misc.scss: -------------------------------------------------------------------------------- 1 | /* Miscellanoeous */ 2 | body, 3 | html { 4 | overflow-x: hidden; 5 | padding-right: 0 !important; // resets padding right added by Bootstrap modal 6 | } 7 | 8 | *:-moz-full-screen, 9 | *:-webkit-full-screen, 10 | *:fullscreen *:-ms-fullscreen { 11 | overflow: auto !important; 12 | } 13 | 14 | .page-body-wrapper { 15 | min-height: calc(100vh - #{$navbar-height}); 16 | @include display-flex(); 17 | @include flex-direction(row); 18 | padding-left: 0; 19 | padding-right: 0; 20 | 21 | &.full-page-wrapper { 22 | width: 100%; 23 | min-height: 100vh; 24 | } 25 | } 26 | 27 | .main-panel { 28 | transition: width $action-transition-duration $action-transition-timing-function, margin $action-transition-duration $action-transition-timing-function; 29 | width: calc(100% - #{$sidebar-width-lg}); 30 | min-height: calc(100vh - #{$navbar-height}); 31 | @include display-flex(); 32 | @include flex-direction(column); 33 | @media (max-width: 991px) { 34 | margin-left: 0; 35 | width: 100%; 36 | } 37 | } 38 | 39 | .content-wrapper { 40 | background: $content-bg; 41 | padding: 1.5rem 1.7rem; 42 | width: 100%; 43 | @include flex-grow(1); 44 | } 45 | 46 | .container-scroller { 47 | overflow: hidden; 48 | } 49 | 50 | .scroll-container { 51 | position: relative; 52 | 53 | &.horizontally { 54 | overflow-x: hidden; 55 | width: 100%; 56 | max-width: 100%; 57 | } 58 | 59 | &.vertically { 60 | overflow-y: hidden; 61 | height: 100%; 62 | max-height: 100%; 63 | } 64 | } 65 | 66 | pre { 67 | background: color(gray-lighter); 68 | padding: 15px; 69 | font-size: 14px; 70 | } -------------------------------------------------------------------------------- /src/assets/scss/_navbar.scss: -------------------------------------------------------------------------------- 1 | /* Navbar */ 2 | .navbar { 3 | font-family: $type-1; 4 | background: $blue-teal-gradient; 5 | padding: 0; 6 | transition: background $action-transition-duration $action-transition-timing-function; 7 | -webkit-transition: background $action-transition-duration $action-transition-timing-function; 8 | -moz-transition: background $action-transition-duration $action-transition-timing-function; 9 | -ms-transition: background $action-transition-duration $action-transition-timing-function; 10 | 11 | .navbar-brand-wrapper { 12 | transition: width $action-transition-duration $action-transition-timing-function, background $action-transition-duration $action-transition-timing-function; 13 | -webkit-transition: width $action-transition-duration $action-transition-timing-function, background $action-transition-duration $action-transition-timing-function; 14 | -moz-transition: width $action-transition-duration $action-transition-timing-function, background $action-transition-duration $action-transition-timing-function; 15 | -ms-transition: width $action-transition-duration $action-transition-timing-function, background $action-transition-duration $action-transition-timing-function; 16 | background: $sidebar-light-bg; 17 | width: $sidebar-width-lg; 18 | height: $navbar-height; 19 | 20 | .navbar-brand { 21 | color: $white; 22 | font-size: 1.5rem; 23 | line-height: 48px; 24 | margin-right: 0; 25 | padding: 0.25rem 0; 26 | 27 | &:active, 28 | &:focus, 29 | &:hover { 30 | color: lighten(color(gray-dark), 10%); 31 | } 32 | 33 | img { 34 | width: calc(#{$sidebar-width-lg} - 130px); 35 | max-width: 100%; 36 | height: 28px; 37 | margin: auto; 38 | vertical-align: middle; 39 | } 40 | } 41 | 42 | .brand-logo-mini { 43 | display: none; 44 | 45 | img { 46 | width: calc(#{$sidebar-width-icon} - 50px); 47 | max-width: 100%; 48 | height: 28px; 49 | margin: auto; 50 | } 51 | } 52 | } 53 | 54 | .navbar-collapse { 55 | padding: 0 15px; 56 | height: $navbar-height; 57 | 58 | .navbar-nav { 59 | .nav-item { 60 | @include display-flex; 61 | @include align-items(center); 62 | margin: 0 0.5rem; 63 | 64 | .nav-link { 65 | color: $white; 66 | } 67 | 68 | &.b-nav-dropdown { 69 | .nav-link { 70 | &.dropdown-toggle { 71 | &::after { 72 | display: none; 73 | } 74 | 75 | .count-indicator { 76 | position: relative; 77 | 78 | .icon { 79 | font-size: 21px; 80 | margin-right: 0; 81 | vertical-align: middle; 82 | } 83 | 84 | .count { 85 | position: absolute; 86 | left: 50%; 87 | width: 1rem; 88 | height: 1rem; 89 | border-radius: 100%; 90 | background: #FF0017; 91 | font-size: 75%; 92 | top: -6px; 93 | font-weight: 600; 94 | line-height: 1rem; 95 | border: none; 96 | text-align: center; 97 | } 98 | } 99 | } 100 | } 101 | 102 | .dropdown-menu { 103 | @extend .dropdownAnimation; 104 | -webkit-box-shadow: 0 0 13px -3px rgba(0,0,0,0.10); 105 | -moz-box-shadow: 0 0 13px -3px rgba(0,0,0,0.10); 106 | box-shadow: 0 0 13px -3px rgba(0,0,0,0.10); 107 | .dropdown-item { 108 | @extend .d-flex; 109 | @extend .align-items-center; 110 | border-bottom: 1px solid lighten(color(gray-light),30%); 111 | margin-bottom: 0; 112 | padding: 11px 30px; 113 | border-bottom: 1px solid $border-color; 114 | 115 | &:last-child { 116 | border-bottom: none; 117 | } 118 | 119 | .badge { 120 | margin-left: 2.5rem; 121 | 122 | .rtl & { 123 | margin-left: 0; 124 | margin-right: 1.25rem; 125 | } 126 | } 127 | 128 | i { 129 | font-size: 17px; 130 | } 131 | 132 | .ellipsis { 133 | max-width: 200px; 134 | overflow: hidden; 135 | text-overflow: ellipsis; 136 | } 137 | 138 | .preview-icon { 139 | width: 40px; 140 | height: 40px; 141 | @include border-radius(100%); 142 | } 143 | 144 | .small-text { 145 | font-size: 0.75rem; 146 | } 147 | } 148 | } 149 | } 150 | } 151 | 152 | &.header-links { 153 | height: $navbar-height; 154 | padding-left: 2%; 155 | 156 | .nav-item { 157 | margin: 0; 158 | 159 | .nav-link { 160 | height: $navbar-height; 161 | font-size: $default-font-size; 162 | padding: 16px 25px; 163 | @include display-flex; 164 | 165 | &.active { 166 | background: rgba($white,0.3); 167 | } 168 | 169 | i { 170 | margin-right: 10px; 171 | font-size: inherit; 172 | 173 | .rtl & { 174 | margin-right: 0; 175 | margin-left: 10px; 176 | } 177 | } 178 | } 179 | } 180 | } 181 | } 182 | } 183 | 184 | &.fixed-top { 185 | + .page-body-wrapper { 186 | padding-top: $navbar-height; 187 | } 188 | } 189 | } -------------------------------------------------------------------------------- /src/assets/scss/_reset.scss: -------------------------------------------------------------------------------- 1 | /* Reset Styles */ 2 | 3 | body { 4 | padding: 0; 5 | margin: 0; 6 | overflow-x: hidden; 7 | } 8 | 9 | .form-control, 10 | .form-control:focus { 11 | -webkit-box-shadow: none; 12 | -moz-box-shadow: none 13 | } 14 | 15 | .form-control { 16 | box-shadow: none 17 | } 18 | 19 | .form-control:focus { 20 | outline: 0; 21 | box-shadow: none 22 | } 23 | 24 | a, 25 | div, 26 | h1, 27 | h2, 28 | h3, 29 | h4, 30 | h5, 31 | p, 32 | span { 33 | text-shadow: none 34 | } 35 | 36 | [type=button]:focus, 37 | a:active, 38 | a:focus, 39 | a:visited, 40 | button::-moz-focus-inner, 41 | input[type=reset]::-moz-focus-inner, 42 | input[type=button]::-moz-focus-inner, 43 | input[type=submit]::-moz-focus-inner, 44 | input[type=file]>input[type=button]::-moz-focus-inner, 45 | select::-moz-focus-inner { 46 | outline: 0 47 | } 48 | 49 | input, 50 | .form-control:focus, 51 | input:focus, 52 | select:focus, 53 | textarea:focus, 54 | button:focus { 55 | outline: none; 56 | outline-width: 0; 57 | outline-color: transparent; 58 | box-shadow: none; 59 | outline-style: none; 60 | } 61 | 62 | textarea { 63 | resize: none; 64 | overflow-x: hidden; 65 | } 66 | 67 | .btn, 68 | .btn-group.open .dropdown-toggle, 69 | .btn:active, 70 | .btn:focus, 71 | .btn:hover, 72 | .btn:visited, 73 | a, 74 | a:active, 75 | a:checked, 76 | a:focus, 77 | a:hover, 78 | a:visited, 79 | body, 80 | button, 81 | button:active, 82 | button:hover, 83 | button:visited, 84 | div, 85 | input, 86 | input:active, 87 | input:focus, 88 | input:hover, 89 | input:visited, 90 | select, 91 | select:active, 92 | select:focus, 93 | select:visited, 94 | textarea, 95 | textarea:active, 96 | textarea:focus, 97 | textarea:hover, 98 | textarea:visited { 99 | -webkit-box-shadow: none; 100 | -moz-box-shadow: none; 101 | box-shadow: none 102 | } 103 | 104 | .btn.active.focus, 105 | .btn.active:focus, 106 | .btn.focus, 107 | .btn:active.focus, 108 | .btn:active:focus, 109 | .btn:focus, 110 | button, 111 | button:active, 112 | button:checked, 113 | button:focus, 114 | button:hover, 115 | button:visited { 116 | outline: 0; 117 | outline-offset: 0 118 | } 119 | 120 | .bootstrap-select .dropdown-toggle:focus { 121 | outline: 0 !important; 122 | outline-offset: 0 123 | } 124 | 125 | .dropdown-menu>li>a:active, 126 | .dropdown-menu>li>a:focus, 127 | .dropdown-menu>li>a:hover, 128 | .dropdown-menu>li>a:visited { 129 | outline: 0 !important 130 | } 131 | 132 | a:focus, 133 | input:focus { 134 | border-color: transparent; 135 | outline: none 136 | } 137 | -------------------------------------------------------------------------------- /src/assets/scss/_sidebar.scss: -------------------------------------------------------------------------------- 1 | /* Sidebar */ 2 | .sidebar { 3 | min-height: calc(100vh - #{$navbar-height}); 4 | background: $sidebar-light-bg; 5 | font-family: $type-1; 6 | padding: 0; 7 | width: $sidebar-width-lg; 8 | z-index: 11; 9 | transition: width $action-transition-duration $action-transition-timing-function, background $action-transition-duration $action-transition-timing-function; 10 | -webkit-transition: width $action-transition-duration $action-transition-timing-function, background $action-transition-duration $action-transition-timing-function; 11 | -moz-transition: width $action-transition-duration $action-transition-timing-function, background $action-transition-duration $action-transition-timing-function; 12 | -ms-transition: width $action-transition-duration $action-transition-timing-function, background $action-transition-duration $action-transition-timing-function; 13 | 14 | .nav { 15 | overflow: hidden; 16 | flex-wrap: nowrap; 17 | flex-direction: column; 18 | padding-top: 30px; 19 | padding-bottom: 50px; 20 | 21 | .nav-item { 22 | .collapse { 23 | z-index: 999; 24 | } 25 | 26 | .collapse.show, 27 | .collapsing { 28 | background: $sidebar-light-menu-active-bg; 29 | } 30 | 31 | .nav-link { 32 | align-items: center; 33 | display: flex; 34 | padding: $sidebar-menu-padding; 35 | white-space: nowrap; 36 | height: $nav-link-height; 37 | color: $sidebar-light-menu-color; 38 | 39 | &[aria-expanded="true"] { 40 | background: $sidebar-light-menu-active-bg; 41 | } 42 | 43 | .menu-icon { 44 | margin-right: 1.25rem; 45 | width: $sidebar-icon-size; 46 | line-height: 1; 47 | .rtl & { 48 | margin-right: 0; 49 | margin-left: 1.25rem; 50 | } 51 | } 52 | 53 | i { 54 | color: $sidebar-light-menu-icon-color; 55 | 56 | &.menu-arrow { 57 | margin-left: auto; 58 | margin-right: 0; 59 | 60 | &:before { 61 | content: "\F35D"; 62 | font-family: "Material Design Icons"; 63 | font-size: 18px; 64 | line-height: 1; 65 | font-style: normal; 66 | vertical-align: middle; 67 | color: rgba($sidebar-light-menu-color,0.5); 68 | } 69 | } 70 | } 71 | 72 | .menu-title { 73 | color: inherit; 74 | display: inline-block; 75 | font-size: $sidebar-menu-font-size; 76 | line-height: 1; 77 | vertical-align: middle; 78 | } 79 | 80 | .badge { 81 | margin-left: auto; 82 | } 83 | 84 | &:hover { 85 | color: darken($sidebar-light-menu-color, 5%); 86 | } 87 | } 88 | 89 | &.nav-profile { 90 | background: $sidebar-profile-bg; 91 | 92 | .nav-link { 93 | font-family: $type-1; 94 | display: block; 95 | height: auto; 96 | padding: $sidebar-profile-padding; 97 | } 98 | 99 | .profile-image { 100 | position: relative; 101 | width: 70px; 102 | height: 70px; 103 | margin: auto; 104 | 105 | img { 106 | width: 70px; 107 | height: 70px; 108 | border-radius: 100%; 109 | } 110 | } 111 | 112 | .profile-name { 113 | margin-top: 0.75rem; 114 | text-align: center; 115 | 116 | .rtl & { 117 | margin-left: auto; 118 | margin-right: 0.75rem; 119 | } 120 | 121 | .designation, 122 | .name { 123 | font-family: $type-1; 124 | margin-bottom: 0; 125 | line-height: 1.5; 126 | font-weight: 500; 127 | } 128 | 129 | .name { 130 | color: $sidebar-light-profile-name-color; 131 | } 132 | 133 | .designation { 134 | color: $sidebar-light-profile-title-color; 135 | font-size: 0.75rem; 136 | } 137 | } 138 | 139 | i { 140 | color: color(white); 141 | font-size: 1rem; 142 | margin-left: auto; 143 | } 144 | } 145 | 146 | &.active { 147 | > .nav-link { 148 | color: $sidebar-light-menu-active-color; 149 | 150 | .menu-title, 151 | i { 152 | color: inherit; 153 | } 154 | } 155 | } 156 | } 157 | 158 | &:not(.sub-menu) { 159 | > .nav-item { 160 | &:hover { 161 | &:not(.nav-profile) { 162 | > .nav-link { 163 | background: $sidebar-light-menu-hover-bg; 164 | color: $sidebar-light-menu-hover-color; 165 | } 166 | } 167 | } 168 | } 169 | } 170 | 171 | &.sub-menu { 172 | margin-bottom: 0; 173 | padding: $sidebar-submenu-padding; 174 | 175 | .nav-item { 176 | .nav-link { 177 | color: $sidebar-light-submenu-color; 178 | padding: $sidebar-submenu-item-padding; 179 | font-size: $sidebar-submenu-font-size; 180 | line-height: 1; 181 | height: auto; 182 | 183 | &.active { 184 | color: $sidebar-light-menu-active-color; 185 | background: transparent; 186 | 187 | &:before { 188 | background: $sidebar-light-menu-active-color; 189 | } 190 | } 191 | } 192 | 193 | &:hover { 194 | > .nav-link { 195 | background: $sidebar-light-submenu-hover-bg; 196 | color: $sidebar-light-submenu-hover-color; 197 | 198 | &:before { 199 | background: $sidebar-light-submenu-hover-color; 200 | } 201 | } 202 | } 203 | } 204 | } 205 | .nav-item{ 206 | &.purchase-button{ 207 | text-align: center; 208 | margin-top: 10px; 209 | padding-left: 15px; 210 | padding-right: 15px; 211 | .nav-link{ 212 | background-color: #d209fa; 213 | @include filter-gradient(#d209fa, #4f81d4, horizontal); 214 | @include background-image(linear-gradient(to right, #d209fa 1%,#4f81d4 100%)); 215 | color: $white; 216 | text-align: center; 217 | display: block; 218 | font-weight: 500; 219 | @include border-radius(4px); 220 | @include transition-duration(0.3s); 221 | font-size: 14px; 222 | &:hover{ 223 | background-color: #d209fa; 224 | @include filter-gradient(#d209fa, #4f81d4, horizontal); 225 | @include background-image(linear-gradient(to right, #d209fa 1%,#4f81d4 100%)); 226 | } 227 | } 228 | &:hover{ 229 | .nav-link{ 230 | background-color: #d209fa !important; 231 | color: $white !important; 232 | } 233 | } 234 | } 235 | } 236 | } 237 | } 238 | /* style for off-canvas menu*/ 239 | @media screen and (max-width: 991px) { 240 | .sidebar-offcanvas { 241 | position: fixed; 242 | max-height: calc(100vh - #{$navbar-height}); 243 | top: $navbar-height; 244 | bottom: 0; 245 | overflow: auto; 246 | right: -$sidebar-width-lg; 247 | -webkit-transition: all 0.25s ease-out; 248 | -o-transition: all 0.25s ease-out; 249 | transition: all 0.25s ease-out; 250 | 251 | &.active { 252 | right: 0; 253 | } 254 | } 255 | } 256 | -------------------------------------------------------------------------------- /src/assets/scss/_typography.scss: -------------------------------------------------------------------------------- 1 | /* Typography */ 2 | 3 | 4 | body { 5 | font-size: 1rem; 6 | font-family: $type-1; 7 | font-weight: initial; 8 | } 9 | 10 | .h1, 11 | .h2, 12 | .h3, 13 | .h4, 14 | .h5, 15 | .h6, 16 | h1, 17 | h2, 18 | h3, 19 | h4, 20 | h5, 21 | h6 { 22 | font-family: $type-1; 23 | } 24 | 25 | p { 26 | font-size: $default-font-size; 27 | } 28 | 29 | .h1, 30 | h1 { 31 | font-size: 2.19rem; 32 | } 33 | 34 | .h2, 35 | h2 { 36 | font-size: 1.88rem; 37 | } 38 | 39 | .h3, 40 | h3 { 41 | font-size: 1.56rem; 42 | } 43 | 44 | .h4, 45 | h4 { 46 | font-size: 1.13rem; 47 | } 48 | 49 | .h5, 50 | h5 { 51 | font-size: 1rem; 52 | } 53 | 54 | .h6, 55 | h6 { 56 | font-size: 0.9375rem; 57 | } 58 | 59 | p { 60 | font-size: 0.88rem; 61 | } 62 | 63 | .display-1 { 64 | font-size: 3.75rem; 65 | @media (max-width: 991px) { 66 | font-size: 3rem; 67 | } 68 | } 69 | 70 | .display-2 { 71 | font-size: 3.125rem; 72 | @media (max-width: 991px) { 73 | font-size: 2.5rem; 74 | } 75 | } 76 | 77 | .display-3 { 78 | font-size: 2.5rem; 79 | @media (max-width: 991px) { 80 | font-size: 2rem; 81 | } 82 | } 83 | 84 | .display-4 { 85 | font-size: 1.875rem; 86 | @media (max-width: 991px) { 87 | font-size: 1.5rem; 88 | } 89 | } 90 | 91 | .display-5 { 92 | font-size: 1.25rem; 93 | @media (max-width: 991px) { 94 | font-size: 1rem; 95 | } 96 | } 97 | 98 | .blockquote { 99 | padding: 1.25rem; 100 | border: 1px solid $border-color; 101 | } 102 | 103 | address { 104 | p { 105 | margin-bottom: 0; 106 | } 107 | } 108 | //blockqoute color variations 109 | @each $color, $value in $theme-colors { 110 | .blockquote-#{$color} { 111 | @include blockquote($value); 112 | } 113 | } 114 | 115 | .page-title { 116 | color: $black; 117 | margin: 0.38rem 0 0.75rem; 118 | } 119 | 120 | .card-title { 121 | color: color(black); 122 | margin-bottom: 1.125rem; 123 | text-transform: capitalize; 124 | 125 | .rtl & { 126 | text-align: right; 127 | } 128 | } 129 | 130 | .card-subtitle { 131 | @extend .text-gray; 132 | font-family: $type-1; 133 | margin-top: 0.625rem; 134 | margin-bottom: 0.625rem; 135 | } 136 | 137 | .card-description { 138 | margin-bottom: 0.9375rem; 139 | font-family: $type-1; 140 | 141 | .rtl & { 142 | text-align: right; 143 | } 144 | } 145 | 146 | .font-weight-normal { 147 | font-weight: 400; 148 | } 149 | 150 | .font-weight-medium { 151 | font-weight: 500; 152 | } 153 | 154 | .font-weight-bold { 155 | font-weight: 600; 156 | } 157 | 158 | .text-small { 159 | font-size: $default-font-size; 160 | } 161 | 162 | .icon-lg { 163 | font-size: 2.5rem; 164 | } 165 | 166 | .icon-md { 167 | font-size: 1.875rem; 168 | } 169 | 170 | .icon-sm { 171 | font-size: 1rem; 172 | } -------------------------------------------------------------------------------- /src/assets/scss/_utilities.scss: -------------------------------------------------------------------------------- 1 | /* Utilities */ 2 | 3 | .grid-margin { 4 | margin-bottom: $grid-gutter-width; 5 | } 6 | .grid-margin-sm-0 { 7 | @media (min-width: 576px) { 8 | margin-bottom: 0; 9 | } 10 | } 11 | .grid-margin-md-0 { 12 | @media (min-width: 768px) { 13 | margin-bottom: 0; 14 | } 15 | } 16 | .grid-margin-lg-0 { 17 | @media (min-width: 992px) { 18 | margin-bottom: 0; 19 | } 20 | } 21 | .grid-margin-xl-0 { 22 | @media (min-width: 1200px) { 23 | margin-bottom: 0; 24 | } 25 | } 26 | .img-lg { 27 | width: 92px; 28 | height: 92px; 29 | } 30 | .img-md { 31 | width: 60px; 32 | height: 60px; 33 | } 34 | .img-sm { 35 | width: 43px; 36 | height: 43px; 37 | } 38 | .img-xs { 39 | width: 37px; 40 | height: 37px; 41 | } 42 | .img-ss { 43 | width: 26px; 44 | height: 26px; 45 | } 46 | .stretch-card { 47 | @include display-flex; 48 | @include align-items(stretch); 49 | @include justify-content(stretch); 50 | >.card{ 51 | width: 100%; 52 | min-width: 100%; 53 | } 54 | } 55 | 56 | .border-right-sm{ 57 | @media (min-width: 576px) { 58 | border-right: $border-width solid $border-color; 59 | } 60 | } 61 | .border-right-md{ 62 | @media (min-width: 768px) { 63 | border-right: $border-width solid $border-color; 64 | } 65 | } 66 | .border-right-lg{ 67 | @media (min-width: 992px) { 68 | border-right: $border-width solid $border-color; 69 | } 70 | } 71 | 72 | .border-left-sm{ 73 | @media (min-width: 576px) { 74 | border-left: $border-width solid $border-color; 75 | } 76 | } 77 | .border-left-md{ 78 | @media (min-width: 768px) { 79 | border-left: $border-width solid $border-color; 80 | } 81 | } 82 | .border-left-lg{ 83 | @media (min-width: 992px) { 84 | border-left: $border-width solid $border-color; 85 | } 86 | } 87 | 88 | .text-gray { 89 | color: #8c8c8c; 90 | } 91 | 92 | .text-black { 93 | color: $black; 94 | } 95 | 96 | .flex-grow { 97 | flex-grow: 1; 98 | } 99 | .ellipsis{ 100 | max-width: 95%; 101 | white-space: nowrap; 102 | text-overflow: ellipsis; 103 | overflow: hidden; 104 | } 105 | .no-wrap{ 106 | white-space: nowrap; 107 | } 108 | .bg-transparent { 109 | background: transparent; 110 | } -------------------------------------------------------------------------------- /src/assets/scss/_variables.scss: -------------------------------------------------------------------------------- 1 | ////////// COLOR SYSTEM ////////// 2 | $dark-blue: #212c43; 3 | $blue: #03a9f3; 4 | $indigo: #6610f2; 5 | $purple: #ab8ce4; 6 | $pink: #E91E63; 7 | $red: #f96868; 8 | $orange: #fb9678; 9 | $yellow: #ffb463; 10 | $green: #00c292; 11 | $teal: #58d8a3; 12 | $cyan: #57c7d4; 13 | $black: #000; 14 | $white: #ffffff; 15 | $white-smoke: #f4f4f4; 16 | $ghost-white: #f7fafc; 17 | $violet: #41478a; 18 | $darkslategray: #2e383e; 19 | $dodger-blue: #3498db; 20 | $blue-teal-gradient: linear-gradient(88deg, #318be3, #04befe); 21 | $blue: #1991EB; 22 | $indigo: #6610f2; 23 | $purple: #745af2; 24 | $pink: #e83e8c; 25 | $red: #FF0017; 26 | $orange: #FFC105; 27 | $yellow: #ffc107; 28 | $green: #08D419; 29 | $teal: #58d8a3; 30 | $cyan: #17a2b8; 31 | $white: #ffffff; 32 | $colors: ( 33 | blue: $blue, 34 | indigo: $indigo, 35 | purple: $purple, 36 | pink: $pink, 37 | red: $red, 38 | orange: $orange, 39 | yellow: $yellow, 40 | green: $green, 41 | teal: $teal, 42 | cyan: $cyan, 43 | white: $white, 44 | white-smoke: #f2f7f8, 45 | gray: $gray-600, 46 | gray-light: #636c72, 47 | gray-lightest: #f7f7f9, 48 | gray-dark: #292b2c 49 | ); 50 | $social-colors: ( 51 | twitter: #1da1f2, 52 | facebook: #3b579d, 53 | google: #dc4a38, 54 | linkedin: #0177b4, 55 | pinterest: #cc2127, 56 | youtube: #e52d27, 57 | github: #333333, 58 | behance: #1769ff, 59 | dribbble: #ea4c89, 60 | reddit: #ff4500 61 | ); 62 | $theme-colors: ( 63 | primary: $dark-blue, 64 | secondary: $gray-300, 65 | success: $green, 66 | info: $purple, 67 | warning: $orange, 68 | danger: $red, 69 | light: $gray-100, 70 | dark: #424964, 71 | teal: $teal, 72 | ); 73 | ////////// COLOR SYSTEM ////////// 74 | 75 | 76 | 77 | ////////// TEMPLATE VARIABLES ////////// 78 | $content-bg: #F6F8FA; 79 | $footer-bg: $content-bg; 80 | $footer-color: color(dark); 81 | $border-color: #f3f3f3; 82 | ////////// TEMPLATE VARIABLES ////////// 83 | 84 | 85 | 86 | ////////// FONTS ////////// 87 | $type-1: 'Poppins', sans-serif; 88 | $default-font-size: 0.875rem; 89 | $text-muted: #c2c2c2; 90 | $body-color: #212529; 91 | ////////// FONT VARIABLES ////////// 92 | 93 | 94 | 95 | ////////// SIDEBAR //////// 96 | $sidebar-width-lg: 255px; 97 | $sidebar-width-icon: 70px; 98 | $sidebar-light-bg: $white; 99 | $sidebar-light-menu-color: #4a4949; 100 | $sidebar-light-menu-active-bg: #f1f6ff; 101 | $sidebar-light-menu-active-color: theme-color(primary); 102 | $sidebar-light-menu-hover-bg: $sidebar-light-menu-active-bg; 103 | $sidebar-light-menu-hover-color: $sidebar-light-menu-color; 104 | $sidebar-light-submenu-color: $sidebar-light-menu-color; 105 | $sidebar-light-submenu-hover-bg: initial; 106 | $sidebar-light-submenu-hover-color: #000; 107 | $sidebar-light-category-color: #999999; 108 | $sidebar-light-menu-icon-color: #404852; 109 | $sidebar-light-profile-name-color: #404852; 110 | $sidebar-light-profile-title-color: #8d9498; 111 | $sidebar-menu-font-size: 0.875rem; 112 | $sidebar-icon-size: 16px; 113 | $sidebar-menu-padding: 1rem 1.875rem; 114 | $nav-link-height: 52px; 115 | $sidebar-submenu-padding: 0 0 0 3.25rem; 116 | $sidebar-submenu-font-size: 0.875rem; 117 | $sidebar-submenu-item-padding: 0.75rem 1rem; 118 | $sidebar-icon-font-size: 0.9375rem; 119 | $sidebar-arrow-font-size: 0.625rem; 120 | $sidebar-profile-bg: transparent; 121 | $sidebar-profile-padding: 0 1.625rem 2.25rem 1.188rem; 122 | $sidebar-mini-menu-padding: 0.8125rem 1rem 0.8125rem 1rem; 123 | ///////// SIDEBAR //////// 124 | 125 | 126 | 127 | ///////// NAVBAR //////// 128 | $navbar-height: 58px; 129 | $navbar-light-color: #202339; 130 | $navbar-font-size: 0.9375rem; 131 | $navbar-icon-font-size: 1.25rem; 132 | ///////// NAVBAR //////// 133 | 134 | 135 | 136 | ///////// BUTTONS //////// 137 | $button-fixed-width: 120px; 138 | $btn-padding-y: 0.56rem; 139 | $btn-padding-x: 1.375rem; 140 | $btn-line-height: 1; 141 | $btn-padding-y-xs: 0.5rem; 142 | $btn-padding-x-xs: 0.75rem; 143 | $btn-padding-y-sm: 0.50rem; 144 | $btn-padding-x-sm: 0.81rem; 145 | $btn-padding-y-lg: 0.94rem; 146 | $btn-padding-x-lg: 1.94rem; 147 | $btn-font-size: 0.875rem; 148 | $btn-font-size-xs: 0.625rem; 149 | $btn-font-size-sm: 0.875rem; 150 | $btn-font-size-lg: 0.875rem; 151 | $btn-border-radius: 0.1875rem; 152 | $btn-border-radius-xs: 0.1875rem; 153 | $btn-border-radius-sm: 0.1875rem; 154 | $btn-border-radius-lg: 0.1875rem; 155 | $social-btn-padding: 18px; 156 | $social-btn-icon-size: 1rem; 157 | ///////// BUTTONS //////// 158 | 159 | 160 | 161 | ///////// FORMS ///////// 162 | $input-bg: color(white); 163 | $input-border-radius: 2px; 164 | $input-placeholder-color: #c9c8c8; 165 | $input-font-size: 0.75rem; 166 | $input-padding-y: 0.56rem; 167 | $input-padding-x: 1.375rem; 168 | $input-line-height: 1; 169 | $input-padding-y-sm: 0.5rem; 170 | $input-padding-x-sm: 0.81rem; 171 | $input-line-height-sm: 1; 172 | $input-padding-y-lg: 0.94rem; 173 | $input-padding-x-lg: 1.94rem; 174 | $input-line-height-lg: 1; 175 | ///////// FORMS ///////// 176 | 177 | 178 | 179 | //////// DROPDOWNS /////// 180 | $dropdown-border-color: $border-color; 181 | $dropdown-divider-bg: $border-color; 182 | $dropdown-link-color: $body-color; 183 | $dropdown-header-color: $body-color; 184 | //////// DROPDOWNS /////// 185 | 186 | 187 | 188 | //////// TABLES //////// 189 | $table-accent-bg: $content-bg; 190 | $table-hover-bg: $content-bg; 191 | $table-cell-padding: .8375rem; 192 | $table-border-color: $border-color; 193 | $table-inverse-bg: #2a2b32; 194 | $table-inverse-color: color(white); 195 | //////// TABLES //////// 196 | 197 | 198 | 199 | ////////// MEASUREMENT AND PROPERTY VARIABLES ////////// 200 | $boxed-container-width: 96%; 201 | $border-property: 1px solid $border-color; 202 | $card-spacing-y: 1.875rem; 203 | $card-padding-y: 1.88rem; 204 | $card-padding-x: 1.81rem; 205 | $grid-gutter-width: 20px; 206 | $action-transition-duration: 0.25s; 207 | $action-transition-timing-function: ease; 208 | ////////// OTHER VARIABLES ////////// 209 | 210 | 211 | 212 | ////////// BREAD CRUMBS VARIABLES ////////// 213 | // default styles 214 | $breadcrumb-padding-y: 0.56rem; 215 | $breadcrumb-padding-x: 1.13rem; 216 | $breadcrumb-item-padding: 0.5rem; 217 | $breadcrumb-margin-bottom: 1rem; 218 | $breadcrumb-font-size: $default-font-size; 219 | $breadcrumb-bg: transparent; 220 | $breadcrumb-border-color: $border-color; 221 | $breadcrumb-divider-color: $gray-600; 222 | $breadcrumb-active-color: $gray-700; 223 | $breadcrumb-divider: "/"; 224 | ////////// BREAD CRUMBS VARIABLES ////////// 225 | 226 | 227 | 228 | ////////// MODALS VARIABLES ////////// 229 | $modal-inner-padding: 15px; 230 | $modal-dialog-margin: 10px; 231 | $modal-dialog-margin-y-sm-up: 30px; 232 | $modal-title-line-height: $line-height-base; 233 | $modal-content-bg: $content-bg; 234 | $modal-content-box-shadow-xs: 0 3px 9px rgba($black,.5); 235 | $modal-content-box-shadow-sm-up: 0 5px 15px rgba($black,.5); 236 | $modal-backdrop-bg: $black; 237 | $modal-backdrop-opacity: 0.5; 238 | $modal-header-border-color: $border-color; 239 | $modal-content-border-color: $border-color; 240 | $modal-footer-border-color: $border-color; 241 | $modal-header-border-width: $border-width; 242 | $modal-content-border-width: $border-width; 243 | $modal-footer-border-width: $border-width; 244 | $modal-header-padding-x: 26px; 245 | $modal-header-padding-y: 25px; 246 | $modal-body-padding-x: 26px; 247 | $modal-body-padding-y: 35px; 248 | $modal-footer-padding-x: 31px; 249 | $modal-footer-padding-y: 15px; 250 | $modal-lg: 90%; 251 | $modal-md: 500px; 252 | $modal-sm: 300px; 253 | $modal-transition: transform 0.4s ease; 254 | ////////// MODALS VARIABLES ////////// 255 | 256 | $primary: $dark-blue; 257 | -------------------------------------------------------------------------------- /src/assets/scss/components/_badges.scss: -------------------------------------------------------------------------------- 1 | /* Badges */ 2 | 3 | 4 | .badge { 5 | border-radius: 0.25rem; 6 | font-size: 0.75rem; 7 | font-weight: initial; 8 | line-height: 1; 9 | padding: 0.25rem 0.375rem; 10 | font-family: $type-1; 11 | 12 | &.badge-pill { 13 | border-radius: 10rem; 14 | } 15 | 16 | &.badge-fw { 17 | min-width: 70px; 18 | } 19 | } 20 | /*Badge variations*/ 21 | @each $color, $value in $theme-colors { 22 | .badge-#{$color} { 23 | @include badge-variations($value); 24 | } 25 | } 26 | /*Badge outlined variations*/ 27 | @each $color, $value in $theme-colors { 28 | .badge-outline-#{$color} { 29 | @include badge-outline-variations($value); 30 | } 31 | } -------------------------------------------------------------------------------- /src/assets/scss/components/_bootstrap-progress.scss: -------------------------------------------------------------------------------- 1 | /* Bootstrap Progress */ 2 | 3 | .progress { 4 | @include border-radius(3px); 5 | height: 8px; 6 | .progress-bar { 7 | @include border-radius(3px); 8 | } 9 | 10 | &.progress-sm{ 11 | height: 0.375rem; 12 | } 13 | &.progress-md { 14 | height: 8px; 15 | } 16 | &.progress-lg { 17 | height: 15px; 18 | } 19 | &.progress-xl { 20 | height: 18px; 21 | } 22 | } -------------------------------------------------------------------------------- /src/assets/scss/components/_breadcrumbs.scss: -------------------------------------------------------------------------------- 1 | /* Breadcrumbs */ 2 | .breadcrumb { 3 | border: $border-width solid $border-color; 4 | 5 | .breadcrumb-item { 6 | font-size: $breadcrumb-font-size; 7 | 8 | &.active {} 9 | } 10 | 11 | &.bg-danger, 12 | &.bg-dark, 13 | &.bg-info, 14 | &.bg-primary, 15 | &.bg-success, 16 | &.bg-warning { 17 | border: none; 18 | 19 | .breadcrumb-item { 20 | color: $white; 21 | 22 | &:before { 23 | color: inherit; 24 | } 25 | 26 | a, 27 | span { 28 | color: inherit; 29 | } 30 | } 31 | } 32 | } 33 | /* inverse breadcrumb */ 34 | @each $color, $value in $theme-colors { 35 | .bg-inverse-#{$color} { 36 | @include breadcrumb-inverse-variant($value); 37 | } 38 | } -------------------------------------------------------------------------------- /src/assets/scss/components/_buttons.scss: -------------------------------------------------------------------------------- 1 | /* Buttons */ 2 | .btn { 3 | font-size: $btn-font-size; 4 | line-height: 1; 5 | font-family: $type-1; 6 | 7 | i { 8 | margin-right: 0.3125rem; 9 | } 10 | 11 | .btn-label { 12 | &:before { 13 | font-size: 1rem; 14 | line-height: 5px; 15 | vertical-align: middle; 16 | } 17 | 18 | &.btn-label-left { 19 | margin-right: 5px; 20 | } 21 | 22 | &.btn-label-right { 23 | margin-left: 5px; 24 | } 25 | } 26 | 27 | &.btn-rounded { 28 | @include border-radius(50px); 29 | } 30 | 31 | &.btn-fw { 32 | min-width: $button-fixed-width; 33 | } 34 | 35 | &.icon-btn { 36 | i { 37 | margin-right: 0; 38 | } 39 | } 40 | 41 | &.social-btn { 42 | padding: $social-btn-padding; 43 | 44 | i { 45 | margin-right: 0; 46 | font-size: $social-btn-icon-size; 47 | } 48 | } 49 | 50 | &.btn-sm { 51 | font-size: $btn-font-size-sm; 52 | } 53 | 54 | &.btn-lg { 55 | font-size: $btn-font-size-lg; 56 | } 57 | 58 | &.btn-xs { 59 | padding: $btn-padding-y-xs $btn-padding-x-xs; 60 | font-size: $btn-font-size-xs; 61 | } 62 | 63 | &.btn-danger, 64 | &.btn-info, 65 | &.btn-teal, 66 | &.btn-warning { 67 | color: $white; 68 | } 69 | 70 | &.btn-light { 71 | color: $black; 72 | border-color: lighten($black, 85%); 73 | } 74 | 75 | &.btn-outline-light { 76 | @include button-outline-variant(theme-color(light), color(white)); 77 | } 78 | 79 | &.btn-outline-secondary { 80 | color: rgba($black, 0.5); 81 | } 82 | 83 | &.btn-inverse-secondary { 84 | background-color: rgba(theme-color(secondary), 0.5); 85 | color: rgba($black, 0.5); 86 | 87 | &:hover { 88 | color: rgba($black, 0.5); 89 | } 90 | } 91 | 92 | &.btn-inverse-light { 93 | background-color: $white; 94 | color: rgba($black, 0.5); 95 | border-color: lighten($black, 85%); 96 | 97 | &:hover { 98 | color: rgba($black, 0.5); 99 | border-color: lighten($black, 85%); 100 | } 101 | } 102 | } 103 | 104 | .btn-group { 105 | border: $border-width solid $border-color; 106 | @include border-radius($btn-border-radius); 107 | &:not(.dropdown){ 108 | .btn { 109 | &:not(.dropdown-toggle){ 110 | border-top: none; 111 | border-bottom: none; 112 | border-left: none; 113 | } 114 | 115 | &:last-child { 116 | border-right: none; 117 | } 118 | 119 | &.btn-primary { 120 | border-color: darken(theme-color(primary),3%); 121 | } 122 | 123 | &.btn-secondary { 124 | border-color: darken(theme-color(secondary),3%); 125 | } 126 | 127 | &.btn-info { 128 | border-color: darken(theme-color(info),3%); 129 | } 130 | 131 | &.btn-warning { 132 | border-color: darken(theme-color(warning),3%); 133 | } 134 | 135 | &.btn-success { 136 | border-color: darken(theme-color(success),3%); 137 | } 138 | 139 | &.btn-danger { 140 | border-color: darken(theme-color(danger),3%); 141 | } 142 | 143 | &.btn-dark { 144 | border-color: darken(theme-color(dark),3%); 145 | } 146 | 147 | &.btn-light { 148 | border-color: darken(theme-color(light),3%); 149 | } 150 | } 151 | } 152 | } 153 | 154 | .btn-toolbar { 155 | .btn-group { 156 | +.btn-group { 157 | @extend .ml-2; 158 | } 159 | } 160 | } 161 | /*social buttons*/ 162 | @each $color, $value in $social-colors { 163 | .btn-#{$color} { 164 | @include social-button(social-color($color)); 165 | } 166 | } 167 | /* inverse buttons */ 168 | @each $color, $value in $theme-colors { 169 | .btn-inverse-#{$color} { 170 | @include button-inverse-variant($value); 171 | } 172 | } -------------------------------------------------------------------------------- /src/assets/scss/components/_cards.scss: -------------------------------------------------------------------------------- 1 | /* Cards */ 2 | 3 | .card { 4 | border: 0; 5 | @include border-radius(2px); 6 | .card-body { 7 | padding: $card-padding-y $card-padding-x; 8 | + .card-body { 9 | padding-top: 0; 10 | } 11 | } 12 | &.card-outline-success{ 13 | border: 1px solid theme-color("success"); 14 | } 15 | &.card-outline-primary{ 16 | border: 1px solid theme-color("primary"); 17 | } 18 | &.card-outline-warning{ 19 | border: 1px solid theme-color("warning"); 20 | } 21 | &.card-outline-danger{ 22 | border: 1px solid theme-color("danger"); 23 | } 24 | &.card-rounded{ 25 | @include border-radius(5px); 26 | } 27 | 28 | &.card-faded { 29 | background: #b5b0b2; 30 | border-color: #b5b0b2; 31 | } 32 | &.card-circle-progress { 33 | color: $white; 34 | text-align: center; 35 | } 36 | } 37 | 38 | @each $color, $value in $theme-colors { 39 | .card-inverse-#{$color} { 40 | @include card-inverse-variant(rgba(theme-color($color), .2), theme-color-level($color, 1), theme-color-level($color, 3)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/assets/scss/components/_carousel.scss: -------------------------------------------------------------------------------- 1 | .carousel { 2 | .carousel-inner{ 3 | .carousel-item{ 4 | img{ 5 | max-width: 100%; 6 | width: 100%; 7 | } 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/assets/scss/components/_dropdown.scss: -------------------------------------------------------------------------------- 1 | /* Dropdowns */ 2 | 3 | .dropdown-menu { 4 | font-size: $default-font-size; 5 | .dropdown-item { 6 | &:active { 7 | background: initial; 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/assets/scss/components/_forms.scss: -------------------------------------------------------------------------------- 1 | /* Forms */ 2 | .input-group-append, 3 | .input-group-prepend { 4 | background: color(white); 5 | color: $input-placeholder-color; 6 | width: auto; 7 | border: none; 8 | 9 | .input-group-text { 10 | background: transparent; 11 | border-color: $border-color; 12 | } 13 | } 14 | 15 | .form-control { 16 | border: 1px solid $border-color; 17 | font-family: $type-1; 18 | font-size: $input-font-size; 19 | padding: $btn-padding-y .75rem; 20 | line-height: 14px; 21 | 22 | &.form-control-lg { 23 | padding: $input-btn-padding-y-lg .75rem; 24 | } 25 | 26 | &.form-control-sm { 27 | padding: $input-btn-padding-y-sm .75rem; 28 | } 29 | } 30 | 31 | select { 32 | &.form-control { 33 | padding: 0.4375rem 0.75rem; 34 | } 35 | } 36 | 37 | .form-group { 38 | label { 39 | font-size: $default-font-size; 40 | line-height: 1; 41 | vertical-align: top; 42 | } 43 | 44 | &.has-danger { 45 | .form-control { 46 | border-color: theme-color(danger); 47 | } 48 | } 49 | .custom-control-inline{ 50 | @include align-items(center); 51 | .custom-control-label{ 52 | padding-top: 10px; 53 | &:before,&:after{ 54 | top: 10px; 55 | } 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/assets/scss/components/_icons.scss: -------------------------------------------------------------------------------- 1 | /* Icons */ 2 | 3 | 4 | .icons-list { 5 | border-left: 1px solid $border-color; 6 | border-bottom: 1px solid $border-color; 7 | 8 | > div { 9 | background: $white; 10 | border-top: 1px solid $border-color; 11 | border-right: 1px solid $border-color; 12 | @include display-flex; 13 | @include align-items(center); 14 | padding: 15px; 15 | font-family: $type-1; 16 | font-size: $default-font-size; 17 | 18 | i { 19 | display: inline-block; 20 | font-size: 20px; 21 | width: 40px; 22 | text-align: left; 23 | color: theme-color(primary); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/assets/scss/components/_pagination.scss: -------------------------------------------------------------------------------- 1 | /* Pagination */ 2 | 3 | .pagination{ 4 | .page-item { 5 | .page-link { 6 | border-color: $border-color; 7 | color: color(black); 8 | font-size: .875rem; 9 | @include transition-duration(0.3s); 10 | &:focus{ 11 | background: inherit; 12 | } 13 | i { 14 | &:before { 15 | font-size: inherit; 16 | line-height: 1; 17 | vertical-align: middle; 18 | } 19 | } 20 | } 21 | &.active, 22 | &:hover, 23 | &:focus, 24 | &:active { 25 | .page-link { 26 | background: theme-color("primary"); 27 | border-color: theme-color("primary"); 28 | color: color(white); 29 | } 30 | } 31 | } 32 | &.flat{ 33 | .page-item{ 34 | .page-link{ 35 | border: none; 36 | @include border-radius(2px); 37 | } 38 | } 39 | } 40 | &.separated{ 41 | .page-item{ 42 | margin-left: 2px; 43 | margin-right: 2px; 44 | &:first-child{ 45 | margin-left: 0; 46 | } 47 | &:last-child{ 48 | margin-right: 0; 49 | } 50 | .page-link{ 51 | @include border-radius(2px); 52 | } 53 | } 54 | } 55 | &.rounded{ 56 | .page-item{ 57 | .page-link{} 58 | &:first-child{ 59 | .page-link{ 60 | @include border-radius(25px 0 0 25px); 61 | } 62 | } 63 | &:last-child{ 64 | .page-link{ 65 | @include border-radius(0 25px 25px 0); 66 | } 67 | } 68 | } 69 | } 70 | &.rounded-flat{ 71 | .page-item{ 72 | margin-right: 3px; 73 | margin-left: 3px; 74 | .page-link{ 75 | border: none; 76 | @include border-radius(50px); 77 | 78 | } 79 | } 80 | } 81 | &.rounded-separated{ 82 | .page-item{ 83 | margin-left: 2px; 84 | margin-right: 2px; 85 | &:first-child{ 86 | margin-left: 0; 87 | .page-link{ 88 | @include border-radius(10px 0 0 10px); 89 | } 90 | } 91 | &:last-child{ 92 | margin-right: 0; 93 | .page-link{ 94 | @include border-radius(0 10px 10px 0); 95 | } 96 | } 97 | .page-link{ 98 | @include border-radius(2px); 99 | } 100 | } 101 | } 102 | } 103 | 104 | 105 | /* pagination variations */ 106 | @each $color, $value in $theme-colors { 107 | .pagination-#{$color} { 108 | @include pagination-variants($value); 109 | } 110 | } -------------------------------------------------------------------------------- /src/assets/scss/components/_preview.scss: -------------------------------------------------------------------------------- 1 | /* Preview */ 2 | .preview-list { 3 | .preview-item { 4 | @include display-flex; 5 | @include flex-direction(row); 6 | @include align-items(flex-start); 7 | padding: 0.75rem 1.5rem; 8 | font-size: 0.875rem; 9 | 10 | &:last-child { 11 | border-bottom: 0; 12 | } 13 | 14 | &:hover { 15 | background: $dropdown-link-hover-bg; 16 | } 17 | 18 | .form-check { 19 | margin-top: 8px; 20 | margin-right: 1rem; 21 | } 22 | 23 | .preview-thumbnail { 24 | color: color(white); 25 | position: relative; 26 | 27 | .preview-icon, 28 | img { 29 | width: 36px; 30 | height: 36px; 31 | border-radius: 100%; 32 | } 33 | 34 | .preview-icon { 35 | padding: 6px; 36 | text-align: center; 37 | 38 | i { 39 | font-size: 1.125rem; 40 | } 41 | } 42 | 43 | .badge { 44 | border: 2px solid color(white); 45 | border-radius: 100%; 46 | bottom: 5px; 47 | display: block; 48 | height: 14px; 49 | left: -5px; 50 | padding: 0; 51 | position: absolute; 52 | width: 14px; 53 | 54 | &.badge-online { 55 | @extend .badge-success; 56 | } 57 | 58 | &.badge-offline { 59 | @extend .badge-info; 60 | } 61 | 62 | &.badge-busy { 63 | @extend .badge-warning; 64 | } 65 | } 66 | } 67 | 68 | .preview-item-content { 69 | line-height: 1; 70 | padding-left: 15px; 71 | 72 | .rtl & { 73 | padding-left: 0; 74 | padding-right: 15px; 75 | } 76 | 77 | &:first-child { 78 | padding-left: 0; 79 | 80 | .rtl & { 81 | padding-right: 0; 82 | } 83 | } 84 | 85 | p { 86 | margin-bottom: 10px; 87 | 88 | .content-category { 89 | font-family: $type-1; 90 | padding-right: 15px; 91 | border-right: 1px solid $border-color; 92 | @extend .text-muted; 93 | } 94 | } 95 | } 96 | 97 | .preview-actions { 98 | @include display-flex; 99 | @include flex-direction(row); 100 | 101 | i { 102 | width: 29px; 103 | color: color(gray-lightest); 104 | height: 29px; 105 | border: 2px solid color(gray-lightest); 106 | border-radius: 100%; 107 | padding: 3px 6px; 108 | display: inline-block; 109 | 110 | &:first-child { 111 | margin-right: 10px; 112 | } 113 | } 114 | } 115 | } 116 | 117 | &.comment-preview { 118 | .preview-item { 119 | padding: 0.87rem 0; 120 | 121 | &:first-child { 122 | padding-top: 0; 123 | } 124 | 125 | p { 126 | line-height: 27px; 127 | } 128 | } 129 | } 130 | 131 | &.bordered { 132 | .preview-item { 133 | border-bottom: 1px solid $border-color; 134 | 135 | &:last-child { 136 | border-bottom: 0; 137 | } 138 | } 139 | } 140 | } -------------------------------------------------------------------------------- /src/assets/scss/components/_tables.scss: -------------------------------------------------------------------------------- 1 | /* Tables */ 2 | 3 | 4 | .table { 5 | margin-bottom: 0; 6 | 7 | thead { 8 | th { 9 | border-top: 0; 10 | border-bottom-width: 1px; 11 | font-family: $type-1; 12 | font-weight: 500; 13 | 14 | i { 15 | margin-left: 0.325rem; 16 | } 17 | } 18 | } 19 | 20 | td, 21 | th { 22 | vertical-align: middle; 23 | font-size: $default-font-size; 24 | line-height: 1; 25 | 26 | img { 27 | max-width: 100%; 28 | } 29 | 30 | .badge { 31 | margin-bottom: 0; 32 | } 33 | } 34 | 35 | &.table-borderless { 36 | border: none; 37 | 38 | td, 39 | th, 40 | tr { 41 | border: none; 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /src/assets/scss/components/_tabs.scss: -------------------------------------------------------------------------------- 1 | /* Tabs */ 2 | 3 | 4 | // Basic Styles 5 | .nav-pills, 6 | .nav-tabs { 7 | margin-bottom: 1rem; 8 | 9 | .nav-item { 10 | .nav-link { 11 | font-family: $type-1; 12 | line-height: 1; 13 | padding: 13px 28px; 14 | font-size: $default-font-size; 15 | color: $black; 16 | @include display-flex; 17 | @include border-radius(2px); 18 | 19 | i { 20 | margin-right: 10px; 21 | } 22 | } 23 | } 24 | } 25 | 26 | .tab-content { 27 | padding: 37px 18px 29px 24px; 28 | font-family: $type-1; 29 | font-size: $default-font-size; 30 | line-height: 1.71; 31 | border: $border-width solid $border-color; 32 | @include border-radius(2px); 33 | } 34 | // Basic Tab Styles 35 | .tab-basic { 36 | border-bottom: none; 37 | 38 | .nav-item { 39 | .nav-link { 40 | &.active { 41 | border: $border-width solid $border-color; 42 | } 43 | } 44 | } 45 | } 46 | 47 | .tab-content-basic { 48 | border: $border-width solid $border-color; 49 | } 50 | // Solid Tab Styles 51 | .tab-solid { 52 | border: none; 53 | 54 | .nav-item { 55 | .nav-link { 56 | border: none; 57 | 58 | &.active { 59 | border: none; 60 | color: $white; 61 | } 62 | } 63 | } 64 | } 65 | 66 | .tab-content-solid { 67 | border: none; 68 | padding-top: 0.875rem; 69 | padding-left: 0; 70 | padding-right: 0; 71 | } 72 | @each $color, $value in $theme-colors { 73 | .tab-solid-#{$color} { 74 | @include tab-solid-variant($value); 75 | } 76 | } 77 | // Minimal Tab Styles 78 | .tab-minimal { 79 | .nav-tabs { 80 | border: none; 81 | 82 | .nav-item { 83 | .nav-link { 84 | border: none; 85 | 86 | &.active {} 87 | 88 | &:first-child { 89 | padding-left: 0; 90 | } 91 | } 92 | } 93 | } 94 | 95 | .tab-content {} 96 | } 97 | @each $color, $value in $theme-colors { 98 | .tab-minimal-#{$color} { 99 | @include tab-minimal-variant($value); 100 | } 101 | } 102 | // Vertical Tab Styles 103 | .vertical-tab { 104 | @include display-flex; 105 | 106 | .nav-tabs { 107 | margin-right: 1.25rem; 108 | @include flex-direction(column); 109 | } 110 | 111 | .tab-content { 112 | margin-bottom: 0; 113 | } 114 | } -------------------------------------------------------------------------------- /src/assets/scss/dashboard.scss: -------------------------------------------------------------------------------- 1 | /* Dashboard */ 2 | .card-statistics { 3 | .highlight-icon { 4 | font-size: 3.125rem; 5 | } 6 | 7 | .highlight-icon-small { 8 | font-size: 2.5rem; 9 | } 10 | 11 | p { 12 | margin-bottom: 0; 13 | } 14 | } -------------------------------------------------------------------------------- /src/assets/scss/landing-screens/_auth.scss: -------------------------------------------------------------------------------- 1 | /* Auth */ 2 | .auth { 3 | .auth-form-dark { 4 | background: rgba($black, .6); 5 | color: $white; 6 | 7 | .form-control { 8 | border-color: rgba($white, .2); 9 | color: $white; 10 | @include input-placeholder { 11 | color: $white; 12 | } 13 | } 14 | } 15 | 16 | .auth-form-light { 17 | background: $white; 18 | color: $black; 19 | 20 | .form-control { 21 | border-color: rgba($black, .2); 22 | color: $black; 23 | @include input-placeholder { 24 | color: $black; 25 | } 26 | } 27 | } 28 | 29 | .auth-form-transparent { 30 | background: transparent; 31 | color: $white; 32 | 33 | form { 34 | .form-group { 35 | .form-control { 36 | padding-left: 1rem; 37 | padding-right: 1rem; 38 | border-color: rgba($white, .2); 39 | } 40 | } 41 | } 42 | } 43 | 44 | form { 45 | .form-group { 46 | position: relative; 47 | 48 | label { 49 | margin-bottom: 0; 50 | vertical-align: bottom; 51 | font-size: 0.8125rem; 52 | font-family: $type-1; 53 | } 54 | 55 | .form-control { 56 | background: transparent; 57 | border-top: 0; 58 | border-left: 0; 59 | border-right: 0; 60 | border-radius: 0; 61 | padding-left: 0; 62 | padding-right: 2.5rem; 63 | font-size: 0.9375rem; 64 | } 65 | 66 | i { 67 | position: absolute; 68 | right: 1rem; 69 | height: 18px; 70 | top: calc((100% - 18px) / 2); 71 | } 72 | } 73 | 74 | .btn { 75 | font-size: 1.25rem; 76 | } 77 | 78 | .auth-link { 79 | font-size: $default-font-size; 80 | 81 | &:hover { 82 | color: initial; 83 | } 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/assets/scss/landing-screens/_error.scss: -------------------------------------------------------------------------------- 1 | /* Error */ 2 | 3 | .error-page { 4 | h1 { 5 | font-size: 9.375rem; 6 | line-height: 1; 7 | @media (max-width: 991px) { 8 | font-size: 8rem; 9 | } 10 | } 11 | h2 { 12 | font-size: 4.375rem; 13 | line-height: 1; 14 | } 15 | .error-page-divider { 16 | @media (min-width: 992px) { 17 | border-left: 3px solid rgba($white, .2); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /src/assets/scss/mixins/_animation.scss: -------------------------------------------------------------------------------- 1 | /* Animation Mixins */ 2 | @keyframes dropdownAnimation { 3 | from { 4 | opacity: 0; 5 | transform: translate3d(0, -30px, 0); 6 | } 7 | 8 | to { 9 | opacity: 1; 10 | transform: none; 11 | transform: translate3d(0, 0px, 0); 12 | } 13 | } 14 | 15 | .dropdownAnimation { 16 | animation-name: dropdownAnimation; 17 | @include animation-duration($action-transition-duration); 18 | @include animation-fill-mode(both); 19 | } 20 | @mixin transition($settings) { 21 | -webkit-transition: $settings; 22 | -moz-transition: $settings; 23 | -ms-transition: $settings; 24 | -o-transition: $settings; 25 | transition: $settings; 26 | } 27 | @keyframes fadeOut { 28 | from { 29 | opacity: 1; 30 | } 31 | 32 | to { 33 | opacity: 0; 34 | } 35 | } 36 | 37 | .fadeOut { 38 | animation-name: fadeOut; 39 | } 40 | 41 | .infinite-spin { 42 | @keyframes spin { 43 | from { 44 | transform: rotate(0deg); 45 | } 46 | 47 | to { 48 | transform: rotate(360deg); 49 | } 50 | } 51 | animation-name: spin; 52 | animation-duration: 3s; 53 | animation-iteration-count: infinite; 54 | animation-timing-function: linear; 55 | } 56 | @keyframes fadeInUp { 57 | from { 58 | opacity: 0; 59 | transform: translate3d(0, 100%, 0); 60 | } 61 | 62 | to { 63 | opacity: 1; 64 | transform: none; 65 | } 66 | } 67 | 68 | .fadeInUp { 69 | animation-name: fadeInUp; 70 | } -------------------------------------------------------------------------------- /src/assets/scss/mixins/_background.scss: -------------------------------------------------------------------------------- 1 | // Background Mixins // 2 | 3 | @mixin bg($color) { 4 | background: $color; 5 | } 6 | @mixin bg-gradient($color1,$color2) { 7 | background: $color1; /* For browsers that do not support gradients */ 8 | background: -webkit-linear-gradient(90deg, $color1, $color2); /* For Safari 5.1 to 6.0 */ 9 | background: -o-linear-gradient(90deg, $color1, $color2); /* For Opera 11.1 to 12.0 */ 10 | background: -moz-linear-gradient(90deg, $color1, $color2); /* For Firefox 3.6 to 15 */ 11 | background: linear-gradient(90deg, $color1, $color2); /* Standard syntax */ 12 | } 13 | -------------------------------------------------------------------------------- /src/assets/scss/mixins/_badges.scss: -------------------------------------------------------------------------------- 1 | // Badge variations 2 | @mixin badge-variations($color) { 3 | border: 1px solid $color; 4 | color: $white; 5 | } 6 | // Badge outlined variations 7 | @mixin badge-outline-variations($color) { 8 | color: $color; 9 | border: 1px solid $color; 10 | } -------------------------------------------------------------------------------- /src/assets/scss/mixins/_blockqoute.scss: -------------------------------------------------------------------------------- 1 | // BlockQuote Mixins // 2 | 3 | @mixin blockquote($color) { 4 | border-color: $color; 5 | .blockquote-footer { 6 | color: $color; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/assets/scss/mixins/_breadcrumbs.scss: -------------------------------------------------------------------------------- 1 | // Breadcrumb color variations 2 | @mixin breadcrumb-inverse-variant($color) { 3 | background: lighten($color, 25%); 4 | border-color: $color; 5 | 6 | .breadcrumb-item { 7 | color: $color; 8 | 9 | &:before { 10 | color: inherit; 11 | } 12 | 13 | a { 14 | color: inherit; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/assets/scss/mixins/_buttons.scss: -------------------------------------------------------------------------------- 1 | @mixin social-button($color) { 2 | background: $color; 3 | color: color(white); 4 | 5 | &:hover { 6 | background: darken($color, 10%); 7 | } 8 | 9 | &.btn-link { 10 | background: none; 11 | color: $color; 12 | 13 | &:hover { 14 | color: darken($color, 10%); 15 | } 16 | } 17 | } 18 | 19 | @mixin button-inverse-variant($color, $color-hover: $white) { 20 | color: $color; 21 | background-color: rgba($color, 0.2); 22 | background-image: none; 23 | border-color: rgba($color, 0); 24 | @include hover { 25 | color: $color-hover; 26 | background-color: $color; 27 | border-color: $color; 28 | } 29 | 30 | &.focus, 31 | &:focus { 32 | box-shadow: 0 0 0 3px rgba($color, .5); 33 | } 34 | 35 | &.disabled, 36 | &:disabled { 37 | color: $color; 38 | background-color: transparent; 39 | } 40 | 41 | &.active, 42 | &:active, 43 | .show > &.dropdown-toggle { 44 | color: $color-hover; 45 | background-color: $color; 46 | border-color: $color; 47 | } 48 | } -------------------------------------------------------------------------------- /src/assets/scss/mixins/_cards.scss: -------------------------------------------------------------------------------- 1 | // Cards Mixins 2 | 3 | @mixin card-inverse-variant($bg, $border, $color) { 4 | background: $bg; 5 | border: 1px solid $border; 6 | color: $color; 7 | } 8 | -------------------------------------------------------------------------------- /src/assets/scss/mixins/_misc.scss: -------------------------------------------------------------------------------- 1 | /* Miscellaneous Mixins */ 2 | 3 | @mixin placeholder { 4 | &::-webkit-input-placeholder {@content} 5 | &:-moz-placeholder {@content} 6 | &::-moz-placeholder {@content} 7 | &:-ms-input-placeholder {@content} 8 | } 9 | 10 | // generic transform 11 | @mixin transform($transforms) { 12 | -moz-transform: $transforms; 13 | -o-transform: $transforms; 14 | -ms-transform: $transforms; 15 | -webkit-transform: $transforms; 16 | transform: $transforms; 17 | } 18 | // rotate 19 | @mixin rotate ($deg) { 20 | @include transform(rotate(#{$deg}deg)); 21 | } 22 | 23 | // scale 24 | @mixin scale($scale) { 25 | @include transform(scale($scale)); 26 | } 27 | // translate 28 | @mixin translate ($x, $y) { 29 | @include transform(translate($x, $y)); 30 | } 31 | // skew 32 | @mixin skew ($x, $y) { 33 | @include transform(skew(#{$x}deg, #{$y}deg)); 34 | } 35 | //transform origin 36 | @mixin transform-origin ($origin) { 37 | moz-transform-origin: $origin; 38 | -o-transform-origin: $origin; 39 | -ms-transform-origin: $origin; 40 | -webkit-transform-origin: $origin; 41 | transform-origin: $origin; 42 | } 43 | //Ellipsis 44 | %ellipsor{ 45 | text-overflow: ellipsis; 46 | overflow: hidden; 47 | max-width:100%; 48 | white-space: nowrap; 49 | } 50 | -------------------------------------------------------------------------------- /src/assets/scss/mixins/_pagination.scss: -------------------------------------------------------------------------------- 1 | // Pagination variations 2 | @mixin pagination-variants($color) { 3 | .page-item { 4 | &.active { 5 | .page-link { 6 | background: $color; 7 | border-color: $color; 8 | } 9 | } 10 | 11 | .page-link { 12 | &:hover { 13 | background: lighten($color,5%); 14 | border-color: $color; 15 | color: $white; 16 | } 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/assets/scss/mixins/_tabs.scss: -------------------------------------------------------------------------------- 1 | // Solid tab variations 2 | @mixin tab-solid-variant($color) { 3 | .nav-link { 4 | &.active { 5 | background: $color; 6 | } 7 | } 8 | } 9 | // Minimal tab variations 10 | @mixin tab-minimal-variant($color) { 11 | .nav-tabs { 12 | .nav-item { 13 | .nav-link { 14 | &.active { 15 | color: $color; 16 | } 17 | } 18 | } 19 | } 20 | 21 | .tab-content { 22 | border-color: $color; 23 | } 24 | } -------------------------------------------------------------------------------- /src/assets/scss/mixins/_text.scss: -------------------------------------------------------------------------------- 1 | @mixin text-color($color) { 2 | color: $color; 3 | } -------------------------------------------------------------------------------- /src/assets/scss/style.scss: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------ 2 | [Master Stylesheet] 3 | 4 | Project: Star Admin Bootstrap Template [Free Version] 5 | Version: 2.0 6 | -------------------------------------------------------------------*/ 7 | 8 | 9 | 10 | /*------------------------------------------------------------------- 11 | ===== Table of Contents ===== 12 | 13 | * Bootstrap functions 14 | * Template variables 15 | * SCSS Compass Functions 16 | * Boostrap Main SCSS 17 | * Template mixins 18 | + Animation Mixins 19 | + Background Mixins 20 | + BlockQuote Mixins 21 | + Breadcrumbs 22 | + Badges Mixins 23 | + Buttons Mixins 24 | + Cards Mixins 25 | + Miscellaneous Mixins 26 | + Paginations 27 | + Tabs 28 | + Text Mixins 29 | * Core Styles 30 | + Reset Styles 31 | + Fonts 32 | + Functions 33 | + Sidebar 34 | + Navbar 35 | + Typography 36 | + Miscellaneous 37 | + Footer 38 | + Layouts 39 | + Utilities 40 | + Demo styles 41 | + Dashboard 42 | * Components 43 | + Badges 44 | + Bootstrap Progress 45 | + Breadcrumbs 46 | + Buttons 47 | + Cards 48 | + Checkboxes and Radios 49 | + Dropdowns 50 | + Forms 51 | + Icons 52 | + Paginations 53 | + Preview 54 | + Tables 55 | + Tabs 56 | * Landing screens 57 | + Auth 58 | + Error 59 | -------------------------------------------------------------------*/ 60 | 61 | 62 | /*-------------------------------------------------------------------*/ 63 | /* === Import Bootstrap functions and variables === */ 64 | @import "~bootstrap/scss/functions"; 65 | @import "~bootstrap/scss/variables"; 66 | 67 | /*-------------------------------------------------------------------*/ 68 | /* === Import template variables === */ 69 | @import "variables"; 70 | 71 | /*-------------------------------------------------------------------*/ 72 | /* === SCSS Compass Functions === */ 73 | @import "~compass-mixins/lib/compass"; 74 | @import "~compass-mixins/lib/animate"; 75 | 76 | /*-------------------------------------------------------------------*/ 77 | /* === Boostrap Main SCSS === */ 78 | @import "~bootstrap/scss/bootstrap"; 79 | 80 | /*-------------------------------------------------------------------*/ 81 | /* === Template mixins === */ 82 | @import "mixins/animation"; 83 | @import "mixins/background"; 84 | @import "mixins/blockqoute"; 85 | @import "mixins/breadcrumbs"; 86 | @import "mixins/badges"; 87 | @import "mixins/buttons"; 88 | @import "mixins/cards"; 89 | @import "mixins/misc"; 90 | @import "mixins/pagination"; 91 | @import "mixins/tabs"; 92 | @import "mixins/text"; 93 | 94 | /*-------------------------------------------------------------------*/ 95 | /* === Core Styles === */ 96 | @import "reset"; 97 | @import "fonts"; 98 | @import "functions"; 99 | @import "sidebar"; 100 | @import "navbar"; 101 | @import "typography"; 102 | @import "misc"; 103 | @import "footer"; 104 | @import "utilities"; 105 | @import "demo"; 106 | @import "dashboard"; 107 | 108 | /*-------------------------------------------------------------------*/ 109 | /* === Components === */ 110 | @import "components/badges"; 111 | @import "components/bootstrap-progress"; 112 | @import "components/breadcrumbs"; 113 | @import "components/buttons"; 114 | @import "components/cards"; 115 | @import "components/carousel"; 116 | @import "components/checkbox-radio"; 117 | @import "components/dropdown"; 118 | @import "components/forms"; 119 | @import "components/icons"; 120 | @import "components/pagination"; 121 | @import "components/preview"; 122 | @import "components/tables"; 123 | @import "components/tabs"; 124 | 125 | /*-------------------------------------------------------------------*/ 126 | /* === Landing screens === */ 127 | @import "landing-screens/auth"; 128 | @import "landing-screens/error"; 129 | 130 | /* === Custom === */ 131 | @import "custom/custom"; 132 | -------------------------------------------------------------------------------- /src/components/guest/error/Error403.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 44 | 45 | 50 | -------------------------------------------------------------------------------- /src/components/guest/error/Error404.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 44 | 45 | 50 | -------------------------------------------------------------------------------- /src/components/guest/login/Login.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 97 | 98 | 103 | -------------------------------------------------------------------------------- /src/components/secure/status-flow/StatusFlowLookup.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 133 | -------------------------------------------------------------------------------- /src/components/secure/status-flow/StatusFlowModal.vue: -------------------------------------------------------------------------------- 1 | 43 | 44 | 69 | -------------------------------------------------------------------------------- /src/components/secure/user-group/UserGroupLookup.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 108 | -------------------------------------------------------------------------------- /src/components/secure/user-group/UserGroupModal.vue: -------------------------------------------------------------------------------- 1 | 45 | 46 | 71 | -------------------------------------------------------------------------------- /src/components/secure/user/UserLookup.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 108 | -------------------------------------------------------------------------------- /src/components/secure/user/UserModal.vue: -------------------------------------------------------------------------------- 1 | 45 | 46 | 71 | -------------------------------------------------------------------------------- /src/components/secure/workflow-props/AdjustmentActivityProps.vue: -------------------------------------------------------------------------------- 1 | 48 | 49 | 118 | -------------------------------------------------------------------------------- /src/components/secure/workflow-props/ExitActivityProps.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 25 | -------------------------------------------------------------------------------- /src/components/secure/workflow-props/NotificationActivityProps.vue: -------------------------------------------------------------------------------- 1 | 99 | 100 | 161 | -------------------------------------------------------------------------------- /src/components/secure/workflow-props/ServiceActivityProps.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 37 | -------------------------------------------------------------------------------- /src/components/secure/workflow-task/WorkflowTask.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /src/components/secure/workflow-task/WorkflowTaskBrowse.vue: -------------------------------------------------------------------------------- 1 | 65 | 66 | 80 | -------------------------------------------------------------------------------- /src/components/secure/workflow/Workflow.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /src/components/secure/workflow/WorkflowBrowse.vue: -------------------------------------------------------------------------------- 1 | 66 | 67 | 81 | -------------------------------------------------------------------------------- /src/components/secure/workflow/WorkflowLookup.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 127 | -------------------------------------------------------------------------------- /src/components/secure/workflow/WorkflowModal.vue: -------------------------------------------------------------------------------- 1 | 49 | 50 | 75 | -------------------------------------------------------------------------------- /src/components/secure/workflow/WorkflowModify.vue: -------------------------------------------------------------------------------- 1 | 89 | 90 | 180 | -------------------------------------------------------------------------------- /src/components/secure/workflow/WorkflowPreview.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 124 | -------------------------------------------------------------------------------- /src/components/theme/fragments/AppFooter.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 19 | 20 | 25 | -------------------------------------------------------------------------------- /src/components/theme/fragments/AppHeader.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 38 | 39 | 43 | -------------------------------------------------------------------------------- /src/components/theme/fragments/AppSidebar.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 28 | 29 | 34 | -------------------------------------------------------------------------------- /src/components/theme/fragments/common/Breadcrumb.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 34 | -------------------------------------------------------------------------------- /src/components/theme/layouts/Full.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | 11 | 13 | -------------------------------------------------------------------------------- /src/components/theme/layouts/Main.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 38 | -------------------------------------------------------------------------------- /src/filters/FormatUnixDate.js: -------------------------------------------------------------------------------- 1 | import moment from 'moment' 2 | 3 | export default function formatUnixDate (value) { 4 | if (value) { 5 | return moment.unix(value / 1000).format('DD-MM-YYYY') 6 | } else { 7 | return '-' 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/filters/FormatUnixTimestamp.js: -------------------------------------------------------------------------------- 1 | import moment from 'moment' 2 | 3 | export default function formatUnixTimestamp (value) { 4 | if (value) { 5 | return moment.unix(value / 1000).format('DD-MM-YYYY h:mm:ss a') 6 | } else { 7 | return '-' 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/filters/FromNow.js: -------------------------------------------------------------------------------- 1 | import moment from 'moment' 2 | 3 | export default function fromNow (value) { 4 | if (value) { 5 | return moment.unix(value / 1000).fromNow() 6 | } else { 7 | return '-' 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/filters/PrettyBool.js: -------------------------------------------------------------------------------- 1 | export default function prettyBool (value) { 2 | if (value === 'Y' || value === '1') { 3 | return 'Yes' 4 | } else { 5 | return 'No' 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/filters/PrettyNull.js: -------------------------------------------------------------------------------- 1 | export default function prettyNull (value) { 2 | if (value) { 3 | return value 4 | } else { 5 | return '-' 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/filters/index.js: -------------------------------------------------------------------------------- 1 | import prettyNull from './PrettyNull.js' 2 | import prettyBool from './PrettyBool.js' 3 | import formatUnixDate from './FormatUnixDate.js' 4 | import formatUnixTimestamp from './FormatUnixTimestamp.js' 5 | import fromNow from './FromNow.js' 6 | 7 | export default { 8 | install (Vue) { 9 | Vue.filter('prettyNull', prettyNull) 10 | Vue.filter('prettyBool', prettyBool) 11 | Vue.filter('formatUnixDate', formatUnixDate) 12 | Vue.filter('formatUnixTimestamp', formatUnixTimestamp) 13 | Vue.filter('fromNow', fromNow) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | // Vue plugins 2 | import Vue from 'vue' 3 | import VueSimpleSuggest from 'vue-simple-suggest' 4 | import VueCodemirror from 'vue-codemirror' 5 | 6 | // components 7 | import App from './App.vue' 8 | import router from './router' 9 | import store from '@/store' 10 | import filters from './filters' 11 | 12 | // JavaScript libraries 13 | import BootstrapVue from 'bootstrap-vue' 14 | import 'codemirror/mode/vue/vue.js' 15 | import 'codemirror/mode/css/css.js' 16 | import 'codemirror/addon/selection/active-line.js' 17 | import 'codemirror/addon/edit/closebrackets.js' 18 | import 'codemirror/addon/edit/closetag.js' 19 | import 'codemirror/addon/edit/matchtags.js' 20 | import 'codemirror/addon/display/autorefresh.js' 21 | 22 | // styles 23 | import '@mdi/font/css/materialdesignicons.min.css' 24 | import 'flag-icon-css/css/flag-icon.min.css' 25 | import 'font-awesome/css/font-awesome.min.css' 26 | import '@fortawesome/fontawesome-free/css/all.min.css' 27 | import '@/assets/scss/style.scss' 28 | import 'codemirror/lib/codemirror.css' 29 | import 'codemirror/theme/eclipse.css' 30 | 31 | // use plugins 32 | Vue.use(BootstrapVue) 33 | Vue.use(VueCodemirror) 34 | Vue.component('vue-simple-suggest', VueSimpleSuggest) 35 | Vue.use(filters) 36 | 37 | // disable Vue production tip 38 | Vue.config.productionTip = false 39 | 40 | // JavaScript globals 41 | window.$ = require('jquery') 42 | window.jQuery = require('jquery') 43 | window.draw2d = require('draw2d') 44 | 45 | new Vue({ 46 | router, 47 | store, 48 | render: h => h(App) 49 | }).$mount('#app') 50 | -------------------------------------------------------------------------------- /src/mixins/AlertMixin.js: -------------------------------------------------------------------------------- 1 | let AlertMixin = { 2 | data: function () { 3 | return { 4 | alertDisplaySeconds: 10, 5 | alertCountDown: 0, 6 | alertMessage: 'An unknown error has occurred.', 7 | alertVariant: 'danger' 8 | } 9 | }, 10 | methods: { 11 | alertCountDownChanged (alertCountDown) { 12 | this.alertCountDown = alertCountDown 13 | }, 14 | showAlert (variant, message) { 15 | this.alertMessage = message || 'An unknown error has occurred.' 16 | this.alertVariant = variant 17 | this.alertCountDown = this.alertDisplaySeconds 18 | }, 19 | showSuccessAlert (message) { 20 | this.showAlert('success', message) 21 | }, 22 | showDangerAlert (message) { 23 | this.showAlert('danger', message) 24 | }, 25 | showWarningAlert (message) { 26 | this.showAlert('warning', message) 27 | }, 28 | showInfoAlert (message) { 29 | this.showAlert('info', message) 30 | } 31 | } 32 | } 33 | 34 | export default AlertMixin 35 | -------------------------------------------------------------------------------- /src/mixins/AutoCompleteMixin.js: -------------------------------------------------------------------------------- 1 | let AutoCompleteMixin = { 2 | props: { 3 | minLength: { 4 | type: Number, 5 | default: 3 6 | }, 7 | maxSuggestions: { 8 | type: Number, 9 | default: 5 10 | } 11 | }, 12 | data: function () { 13 | return { 14 | autoCompleteStyles: { 15 | vueSimpleSuggest: 'position-relative', 16 | inputWrapper: '', 17 | defaultInput: 'form-control', 18 | suggestions: 'suggest-list list-group position-absolute', 19 | suggestItem: 'suggest-list-item list-group-item' 20 | } 21 | } 22 | } 23 | } 24 | 25 | export default AutoCompleteMixin 26 | -------------------------------------------------------------------------------- /src/mixins/DisabledClassMixin.js: -------------------------------------------------------------------------------- 1 | let DisabledClassMixin = { 2 | methods: { 3 | disabledClass (item) { 4 | return item.disabled === 'Y' ? 'line-through' : '' 5 | } 6 | } 7 | } 8 | 9 | export default DisabledClassMixin 10 | -------------------------------------------------------------------------------- /src/mixins/PagingTableMixin.js: -------------------------------------------------------------------------------- 1 | let PagingTableMixin = { 2 | methods: { 3 | pagingInfo (pageIndex, pageSize, totalRows) { 4 | let displayedRow 5 | if (totalRows <= pageSize) { 6 | displayedRow = totalRows 7 | } else { 8 | let startIndex = (pageIndex - 1) * pageSize + 1 9 | let endIndex = startIndex + pageSize - 1 10 | if (endIndex >= totalRows) { 11 | displayedRow = startIndex + '-' + totalRows 12 | } else { 13 | displayedRow = startIndex + '-' + endIndex 14 | } 15 | } 16 | return 'Showing ' + displayedRow + ' of ' + totalRows 17 | } 18 | } 19 | } 20 | 21 | export default PagingTableMixin 22 | -------------------------------------------------------------------------------- /src/mixins/StatusFlowTableMixin.js: -------------------------------------------------------------------------------- 1 | import StatusFlowService from '@/services/StatusFlowService' 2 | 3 | let StatusFlowTableMixin = { 4 | props: { 5 | defaultStatusFlowTableFilter: { 6 | type: String, 7 | default: null 8 | }, 9 | statusTypeId: { 10 | type: String, 11 | default: null 12 | } 13 | }, 14 | data: function () { 15 | return { 16 | statusFlowTableFilter: this.defaultStatusFlowTableFilter, 17 | statusFlowTableBusy: false, 18 | statusFlowTableTotalRows: 0, 19 | statusFlowTableCurrentPage: 1, 20 | statusFlowTablePerPage: 10, 21 | statusFlowTablePageOptions: [10, 25, 50], 22 | statusFlowTableFields: { 23 | statusFlowId: { 24 | label: 'ID', 25 | sortable: true 26 | }, 27 | description: { 28 | label: 'Description', 29 | sortable: true 30 | } 31 | } 32 | } 33 | }, 34 | methods: { 35 | statusFlowDataProvider (ctx) { 36 | let self = this 37 | return StatusFlowService.statusFlows({ 38 | pageIndex: ctx.currentPage - 1, 39 | pageSize: ctx.perPage, 40 | orderByField: ctx.sortDesc ? '-' + ctx.sortBy : ctx.sortBy, 41 | filter: ctx.filter, 42 | statusTypeId: this.statusTypeId 43 | }).then(function (response) { 44 | self.statusFlowTableTotalRows = response.data.totalRows 45 | return response.data.statusFlowList || [] 46 | }) 47 | }, 48 | refreshStatusFlowTable () { 49 | this.$refs.statusFlowTable.refresh() 50 | } 51 | }, 52 | watch: { 53 | statusTypeId: function (val) { 54 | this.refreshStatusFlowTable() 55 | } 56 | } 57 | } 58 | 59 | export default StatusFlowTableMixin 60 | -------------------------------------------------------------------------------- /src/mixins/StatusItemTableMixin.js: -------------------------------------------------------------------------------- 1 | import StatusItemService from '@/services/StatusItemService' 2 | 3 | let StatusItemTableMixin = { 4 | props: { 5 | defaultStatusTypeId: { 6 | type: String, 7 | default: null 8 | }, 9 | defaultStatusItemTableFilter: { 10 | type: String, 11 | default: null 12 | } 13 | }, 14 | data: function () { 15 | return { 16 | statusTypeId: this.defaultStatusTypeId, 17 | statusItemTableFilter: this.defaultStatusItemTableFilter, 18 | statusItemTableBusy: false, 19 | statusItemTableTotalRows: 0, 20 | statusItemTableCurrentPage: 1, 21 | statusItemTablePerPage: 10, 22 | statusItemTablePageOptions: [10, 25, 50], 23 | statusItemTableFields: { 24 | statusId: { 25 | label: 'ID', 26 | sortable: true 27 | }, 28 | description: { 29 | label: 'Description', 30 | sortable: true 31 | } 32 | } 33 | } 34 | }, 35 | methods: { 36 | statusItemDataProvider (ctx) { 37 | let self = this 38 | return StatusItemService.statusItems({ 39 | pageIndex: ctx.currentPage - 1, 40 | pageSize: ctx.perPage, 41 | orderByField: ctx.sortDesc ? '-' + ctx.sortBy : ctx.sortBy, 42 | filter: ctx.filter, 43 | statusTypeId: this.statusTypeId 44 | }).then(function (response) { 45 | self.statusItemTableTotalRows = response.data.totalRows 46 | return response.data.statusItemList || [] 47 | }) 48 | }, 49 | refreshStatusItemTable () { 50 | this.$refs.statusItemTable.refresh() 51 | } 52 | } 53 | } 54 | 55 | export default StatusItemTableMixin 56 | -------------------------------------------------------------------------------- /src/mixins/UserGroupTableMixin.js: -------------------------------------------------------------------------------- 1 | import SecurityService from '@/services/SecurityService' 2 | 3 | let UserGroupTableMixin = { 4 | props: { 5 | defaultUserGroupTableFilter: { 6 | type: String, 7 | default: null 8 | } 9 | }, 10 | data: function () { 11 | return { 12 | userGroupTableFilter: this.defaultUserGroupTableFilter, 13 | userGroupTableBusy: false, 14 | userGroupTableTotalRows: 0, 15 | userGroupTableCurrentPage: 1, 16 | userGroupTablePerPage: 10, 17 | userGroupTablePageOptions: [10, 25, 50], 18 | userGroupTableFields: { 19 | userGroupId: { 20 | label: 'ID', 21 | sortable: true 22 | }, 23 | description: { 24 | label: 'User Group', 25 | sortable: true 26 | } 27 | } 28 | } 29 | }, 30 | methods: { 31 | userGroupDataProvider (ctx) { 32 | let self = this 33 | return SecurityService.userGroups({ 34 | pageIndex: ctx.currentPage - 1, 35 | pageSize: ctx.perPage, 36 | orderByField: ctx.sortDesc ? '-' + ctx.sortBy : ctx.sortBy, 37 | filter: ctx.filter 38 | }).then(function (response) { 39 | self.userGroupTableTotalRows = response.data.totalRows 40 | return response.data.userGroupList || [] 41 | }) 42 | }, 43 | refreshUserGroupTable () { 44 | this.$refs.userGroupTable.refresh() 45 | } 46 | } 47 | } 48 | 49 | export default UserGroupTableMixin 50 | -------------------------------------------------------------------------------- /src/mixins/UserTableMixin.js: -------------------------------------------------------------------------------- 1 | import SecurityService from '@/services/SecurityService' 2 | 3 | let UserTableMixin = { 4 | props: { 5 | defaultUserTableFilter: { 6 | type: String, 7 | default: null 8 | } 9 | }, 10 | data: function () { 11 | return { 12 | userTableFilter: this.defaultUserTableFilter, 13 | userTableBusy: false, 14 | userTableTotalRows: 0, 15 | userTableCurrentPage: 1, 16 | userTablePerPage: 10, 17 | userTablePageOptions: [10, 25, 50], 18 | userTableFields: { 19 | userId: { 20 | label: 'ID', 21 | sortable: true 22 | }, 23 | userFullName: { 24 | label: 'User Full Name', 25 | sortable: true 26 | } 27 | } 28 | } 29 | }, 30 | methods: { 31 | userDataProvider (ctx) { 32 | let self = this 33 | return SecurityService.users({ 34 | pageIndex: ctx.currentPage - 1, 35 | pageSize: ctx.perPage, 36 | orderByField: ctx.sortDesc ? '-' + ctx.sortBy : ctx.sortBy, 37 | filter: ctx.filter 38 | }).then(function (response) { 39 | self.userTableTotalRows = response.data.totalRows 40 | return response.data.userList || [] 41 | }) 42 | }, 43 | refreshUserTable () { 44 | this.$refs.userTable.refresh() 45 | } 46 | } 47 | } 48 | 49 | export default UserTableMixin 50 | -------------------------------------------------------------------------------- /src/mixins/WorkflowCrowdProcessMixin.js: -------------------------------------------------------------------------------- 1 | let WorkflowCrowdProcessMixin = { 2 | data () { 3 | return { 4 | crowdTypeEnumId: 'WF_CROWD_USER', 5 | userId: '', 6 | userFullName: '', 7 | userGroupId: '', 8 | userGroupDescription: '' 9 | } 10 | }, 11 | methods: { 12 | crowdName (crowd) { 13 | if (crowd.crowdTypeEnumId === 'WF_CROWD_USER') { 14 | return crowd.userFullName 15 | } else if (crowd.crowdTypeEnumId === 'WF_CROWD_USER_GROUP') { 16 | return crowd.userGroupDescription 17 | } else { 18 | return 'Initiator' 19 | } 20 | }, 21 | selectUserRecord (record) { 22 | this.userId = record.userId 23 | this.userFullName = record.userFullName 24 | }, 25 | selectUserGroupRecord (record) { 26 | this.userGroupId = record.userGroupId 27 | this.userGroupDescription = record.description 28 | } 29 | } 30 | } 31 | 32 | export default WorkflowCrowdProcessMixin 33 | -------------------------------------------------------------------------------- /src/mixins/WorkflowProcessMixin.js: -------------------------------------------------------------------------------- 1 | let WorkflowProcessMixin = { 2 | props: { 3 | workflow: Object, 4 | userData: Object 5 | }, 6 | data: function () { 7 | return { 8 | mutableUserData: this.userData 9 | } 10 | }, 11 | methods: { 12 | save () { 13 | this.$emit('save', this.mutableUserData) 14 | }, 15 | cancel () { 16 | this.$emit('cancel') 17 | } 18 | } 19 | } 20 | 21 | export default WorkflowProcessMixin 22 | -------------------------------------------------------------------------------- /src/mixins/WorkflowTableMixin.js: -------------------------------------------------------------------------------- 1 | import WorkflowService from '@/services/WorkflowService' 2 | 3 | let WorkflowTableMixin = { 4 | props: { 5 | defaultWorkflowTypeEnumId: { 6 | type: String, 7 | default: null 8 | }, 9 | defaultWorkflowTableFilter: { 10 | type: String, 11 | default: null 12 | } 13 | }, 14 | data: function () { 15 | return { 16 | workflowTypeEnumId: this.defaultWorkflowTypeEnumId, 17 | workflowTableFilter: this.defaultWorkflowTableFilter, 18 | workflowTableBusy: false, 19 | workflowTableTotalRows: 0, 20 | workflowTableCurrentPage: 1, 21 | workflowTablePerPage: 10, 22 | workflowTablePageOptions: [10, 25, 50], 23 | workflowTableFields: { 24 | workflowId: { 25 | label: 'ID', 26 | sortable: true 27 | }, 28 | workflowName: { 29 | label: 'Workflow Name', 30 | sortable: true 31 | }, 32 | workflowTypeName: { 33 | label: 'Workflow Type', 34 | sortable: true 35 | } 36 | } 37 | } 38 | }, 39 | methods: { 40 | workflowDataProvider (ctx) { 41 | let self = this 42 | return WorkflowService.workflows({ 43 | pageIndex: ctx.currentPage - 1, 44 | pageSize: ctx.perPage, 45 | orderByField: ctx.sortDesc ? '-' + ctx.sortBy : ctx.sortBy, 46 | filter: ctx.filter, 47 | workflowTypeEnumId: this.workflowTypeEnumId 48 | }).then(function (response) { 49 | self.workflowTableTotalRows = response.data.totalRows 50 | return response.data.workflowList || [] 51 | }) 52 | }, 53 | workflowStatusClass (item) { 54 | return item.disabled === 'Y' ? 'line-through' : '' 55 | }, 56 | refreshWorkflowTable () { 57 | this.$refs.workflowTable.refresh() 58 | } 59 | } 60 | } 61 | 62 | export default WorkflowTableMixin 63 | -------------------------------------------------------------------------------- /src/mixins/WorkflowTaskTableMixin.js: -------------------------------------------------------------------------------- 1 | import WorkflowService from '@/services/WorkflowService' 2 | 3 | let WorkflowTaskTableMixin = { 4 | props: { 5 | defaultWorkflowTypeEnumId: { 6 | type: String, 7 | default: null 8 | }, 9 | defaultTaskTableFilter: { 10 | type: String, 11 | default: null 12 | }, 13 | defaultTaskTableView: { 14 | type: String, 15 | default: 'ALL_TASKS' 16 | } 17 | }, 18 | data: function () { 19 | return { 20 | workflowTypeEnumId: this.defaultWorkflowTypeEnumId, 21 | taskTableFilter: this.defaultTaskTableFilter, 22 | taskTableBusy: false, 23 | taskTableTotalRows: 0, 24 | taskTableCurrentPage: 1, 25 | taskTablePerPage: 10, 26 | taskTablePageOptions: [10, 25, 50], 27 | taskTableView: this.defaultTaskTableView, 28 | taskTableViewOptions: [ 29 | { id: 'ALL_TASKS', name: 'All Tasks' }, 30 | { id: 'APPROVAL_TASKS', name: 'Approval Tasks' }, 31 | { id: 'VARIABLE_TASKS', name: 'Variable Tasks' }, 32 | { id: 'MANUAL_TASKS', name: 'Manual Tasks' } 33 | ], 34 | taskTableFields: { 35 | taskId: { 36 | label: 'ID', 37 | sortable: true 38 | }, 39 | workflowName: { 40 | label: 'Workflow Name', 41 | sortable: true 42 | }, 43 | taskTypeDescription: { 44 | label: 'Task Type', 45 | sortable: true 46 | }, 47 | statusDescription: { 48 | label: 'Status', 49 | sortable: true 50 | }, 51 | instanceTimeoutDate: { 52 | label: 'Due Date', 53 | sortable: true 54 | } 55 | } 56 | } 57 | }, 58 | computed: { 59 | taskTableViewName: function () { 60 | for (let i = 0; i < this.taskTableViewOptions.length; i++) { 61 | if (this.taskTableViewOptions[i].id === this.taskTableView) { 62 | return this.taskTableViewOptions[i].name 63 | } 64 | } 65 | return 'Unknown' 66 | } 67 | }, 68 | methods: { 69 | taskDataProvider (ctx) { 70 | let self = this 71 | switch (this.taskTableView) { 72 | case 'APPROVAL_TASKS': { 73 | return WorkflowService.workflowTasks({ 74 | pageIndex: ctx.currentPage - 1, 75 | pageSize: ctx.perPage, 76 | orderByField: ctx.sortDesc ? '-' + ctx.sortBy : ctx.sortBy, 77 | filter: ctx.filter, 78 | workflowTypeEnumId: this.workflowTypeEnumId, 79 | workflowDisabled: 'N', 80 | instanceStatusId: 'WF_INST_STAT_ACTIVE', 81 | taskTypeEnumId: 'WF_TASK_APPROVAL', 82 | assignedUserId: self.$store.state.userId 83 | }).then(function (response) { 84 | self.taskTableTotalRows = response.data.totalRows 85 | return response.data.taskList || [] 86 | }) 87 | } 88 | case 'VARIABLE_TASKS': { 89 | return WorkflowService.workflowTasks({ 90 | pageIndex: ctx.currentPage - 1, 91 | pageSize: ctx.perPage, 92 | orderByField: ctx.sortDesc ? '-' + ctx.sortBy : ctx.sortBy, 93 | filter: ctx.filter, 94 | workflowTypeEnumId: this.workflowTypeEnumId, 95 | workflowDisabled: 'N', 96 | instanceStatusId: 'WF_INST_STAT_ACTIVE', 97 | taskTypeEnumId: 'WF_TASK_VARIABLE', 98 | assignedUserId: self.$store.state.userId 99 | }).then(function (response) { 100 | self.taskTableTotalRows = response.data.totalRows 101 | return response.data.taskList || [] 102 | }) 103 | } 104 | case 'MANUAL_TASKS': { 105 | return WorkflowService.workflowTasks({ 106 | pageIndex: ctx.currentPage - 1, 107 | pageSize: ctx.perPage, 108 | orderByField: ctx.sortDesc ? '-' + ctx.sortBy : ctx.sortBy, 109 | filter: ctx.filter, 110 | workflowTypeEnumId: this.workflowTypeEnumId, 111 | workflowDisabled: 'N', 112 | instanceStatusId: 'WF_INST_STAT_ACTIVE', 113 | taskTypeEnumId: 'WF_TASK_MANUAL', 114 | assignedUserId: self.$store.state.userId 115 | }).then(function (response) { 116 | self.taskTableTotalRows = response.data.totalRows 117 | return response.data.taskList || [] 118 | }) 119 | } 120 | default: { 121 | return WorkflowService.workflowTasks({ 122 | pageIndex: ctx.currentPage - 1, 123 | pageSize: ctx.perPage, 124 | orderByField: ctx.sortDesc ? '-' + ctx.sortBy : ctx.sortBy, 125 | filter: ctx.filter, 126 | workflowTypeEnumId: this.workflowTypeEnumId, 127 | workflowDisabled: 'N', 128 | instanceStatusId: 'WF_INST_STAT_ACTIVE', 129 | assignedUserId: self.$store.state.userId 130 | }).then(function (response) { 131 | self.taskTableTotalRows = response.data.totalRows 132 | return response.data.taskList || [] 133 | }) 134 | } 135 | } 136 | }, 137 | setTaskTableView (view) { 138 | this.taskTableView = view.id 139 | this.$refs.taskTable.refresh() 140 | }, 141 | refreshTaskTable () { 142 | this.$refs.taskTable.refresh() 143 | } 144 | } 145 | } 146 | 147 | export default WorkflowTaskTableMixin 148 | -------------------------------------------------------------------------------- /src/mixins/WorkflowTimeoutProcessMixin.js: -------------------------------------------------------------------------------- 1 | import UomService from '@/services/UomService' 2 | 3 | let WorkflowTimeoutProcessMixin = { 4 | data () { 5 | return { 6 | mutableUserData: { 7 | timeIntervals: [], 8 | timeoutUomId: this.userData.timeoutUomId 9 | } 10 | } 11 | }, 12 | methods: { 13 | async loadInternal () { 14 | let self = this 15 | UomService.uom({ 16 | uomTypeEnumId: 'UT_TIME_FREQ_MEASURE', 17 | orderByField: 'description' 18 | }).then(function (response) { 19 | self.mutableUserData.timeIntervals = response.data || [] 20 | }) 21 | } 22 | }, 23 | mounted () { 24 | this.loadInternal() 25 | } 26 | } 27 | 28 | export default WorkflowTimeoutProcessMixin 29 | -------------------------------------------------------------------------------- /src/navigation/MainMenu.js: -------------------------------------------------------------------------------- 1 | export default { 2 | items: [{ 3 | label: 'Workflows', 4 | iconClass: 'fas fa-play', 5 | url: 'Workflows' 6 | }, { 7 | label: 'Tasks', 8 | iconClass: 'fas fa-inbox', 9 | url: 'WorkflowTasks' 10 | }] 11 | } 12 | -------------------------------------------------------------------------------- /src/router.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import store from '@/store' 4 | 5 | import Main from '@/components/theme/layouts/Main' 6 | import Full from '@/components/theme/layouts/Full' 7 | 8 | Vue.use(Router) 9 | 10 | const router = new Router({ 11 | base: process.env.BASE_URL, 12 | routes: [{ 13 | name: 'Guest', 14 | path: '/', 15 | component: Full, 16 | redirect: { name: 'Login' }, 17 | children: [ 18 | { 19 | name: 'Login', 20 | path: 'login', 21 | component: () => import('@/components/guest/login/Login'), 22 | meta: { 23 | secure: false 24 | } 25 | } 26 | ] 27 | }, { 28 | name: 'Secure', 29 | path: '/secure', 30 | component: Main, 31 | redirect: { name: 'Workflows' }, 32 | meta: { 33 | secure: true 34 | }, 35 | children: [{ 36 | name: 'Workflows', 37 | path: 'workflow', 38 | component: () => import('@/components/secure/workflow/Workflow'), 39 | redirect: { name: 'BrowseWorkflows' }, 40 | meta: { 41 | secure: true 42 | }, 43 | children: [{ 44 | name: 'BrowseWorkflows', 45 | path: 'browse', 46 | component: () => import('@/components/secure/workflow/WorkflowBrowse'), 47 | meta: { 48 | secure: true 49 | } 50 | }, { 51 | name: 'ViewWorkflow', 52 | path: ':id', 53 | component: () => import('@/components/secure/workflow/WorkflowView'), 54 | meta: { 55 | secure: true 56 | } 57 | }, { 58 | name: 'CreateWorkflow', 59 | path: 'create', 60 | component: () => import('@/components/secure/workflow/WorkflowCreate'), 61 | meta: { 62 | secure: true 63 | } 64 | }, { 65 | name: 'ModifyWorkflow', 66 | path: ':id/modify', 67 | component: () => import('@/components/secure/workflow/WorkflowModify'), 68 | meta: { 69 | secure: true 70 | } 71 | }, { 72 | name: 'DesignWorkflow', 73 | path: ':id/design', 74 | component: () => import('@/components/secure/workflow/WorkflowDesigner'), 75 | meta: { 76 | secure: true 77 | } 78 | }] 79 | }, { 80 | name: 'WorkflowTasks', 81 | path: 'workflow-task', 82 | component: () => import('@/components/secure/workflow-task/WorkflowTask'), 83 | redirect: { name: 'BrowseWorkflowTasks' }, 84 | meta: { 85 | secure: true 86 | }, 87 | children: [{ 88 | name: 'BrowseWorkflowTasks', 89 | path: 'browse', 90 | component: () => import('@/components/secure/workflow-task/WorkflowTaskBrowse'), 91 | meta: { 92 | secure: true 93 | } 94 | }, { 95 | name: 'ViewWorkflowTask', 96 | path: ':id', 97 | component: () => import('@/components/secure/workflow-task/WorkflowTaskView'), 98 | meta: { 99 | secure: true 100 | } 101 | }] 102 | }] 103 | }, { 104 | name: 'Error', 105 | path: '*', 106 | component: Full, 107 | redirect: '/error/404', 108 | children: [ 109 | { 110 | name: 'Error404', 111 | path: '/error/404', 112 | component: () => import('@/components/guest/error/Error404'), 113 | meta: { 114 | secure: false 115 | } 116 | }, 117 | { 118 | name: 'Error403', 119 | path: '/error/403', 120 | component: () => import('@/components/guest/error/Error403'), 121 | meta: { 122 | secure: false 123 | } 124 | } 125 | ] 126 | }] 127 | }) 128 | 129 | router.beforeEach((to, from, next) => { 130 | if (to.meta.secure && !store.state.userAuthenticated) { 131 | store.dispatch('setRequestPath', { 132 | requestPath: to.path 133 | }) 134 | next('/login') 135 | } else { 136 | next() 137 | } 138 | }) 139 | 140 | export default router 141 | -------------------------------------------------------------------------------- /src/services/EntityFieldService.js: -------------------------------------------------------------------------------- 1 | import SecureEndpoint from '@/services/SecureEndpoint' 2 | 3 | export default { 4 | entityFields (payload) { 5 | return SecureEndpoint().get('/moqui-workflow/entity/field', { 6 | params: payload 7 | }) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/services/EnumService.js: -------------------------------------------------------------------------------- 1 | import SecureEndpoint from '@/services/SecureEndpoint' 2 | 3 | export default { 4 | enum (payload) { 5 | return SecureEndpoint().get('/moqui-workflow/basic/enum', { 6 | params: payload 7 | }) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/services/PublicEndpoint.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import store from '@/store' 3 | import NProgress from 'nprogress' 4 | 5 | export default () => { 6 | // create axios instance 7 | let instance = axios.create({ 8 | baseURL: process.env.VUE_APP_API_BASE_PATH, 9 | headers: { 10 | 'sessionToken': `${store.state.sessionToken}` 11 | } 12 | }) 13 | 14 | // add interceptors 15 | instance.interceptors.request.use(function (config) { 16 | NProgress.start() 17 | return config 18 | }) 19 | instance.interceptors.response.use(function (response) { 20 | NProgress.done() 21 | return response 22 | }) 23 | 24 | // return instance 25 | return instance 26 | } 27 | -------------------------------------------------------------------------------- /src/services/SecureEndpoint.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import store from '@/store' 3 | import NProgress from 'nprogress' 4 | 5 | export default () => { 6 | // create axios instance 7 | let instance = axios.create({ 8 | baseURL: process.env.VUE_APP_API_BASE_PATH, 9 | headers: { 10 | 'api_key': `${store.state.apiKey}`, 11 | 'sessionToken': `${store.state.sessionToken}` 12 | } 13 | }) 14 | 15 | // add interceptors 16 | instance.interceptors.request.use(function (config) { 17 | NProgress.start() 18 | return config 19 | }) 20 | instance.interceptors.response.use(function (response) { 21 | NProgress.done() 22 | return response 23 | }, function (error) { 24 | NProgress.done() 25 | if (error.response.status === 401) { 26 | window.location.href = process.env.BASE_URL 27 | } 28 | return Promise.reject(error) 29 | }) 30 | 31 | // return instance 32 | return instance 33 | } 34 | -------------------------------------------------------------------------------- /src/services/SecurityService.js: -------------------------------------------------------------------------------- 1 | import SecureEndpoint from '@/services/SecureEndpoint' 2 | import PublicEndpoint from '@/services/PublicEndpoint' 3 | 4 | export default { 5 | userGroups (payload) { 6 | return SecureEndpoint().get('/moqui-workflow/security/userGroup', { 7 | params: payload 8 | }) 9 | }, 10 | users (payload) { 11 | return SecureEndpoint().get('/moqui-workflow/security/user', { 12 | params: payload 13 | }) 14 | }, 15 | loginUser (username, password) { 16 | let authorization = 'Basic ' + btoa(username + ':' + password) 17 | return PublicEndpoint().post('/moqui-workflow/security/user/login', {}, { 18 | headers: { 19 | 'Authorization': authorization 20 | } 21 | }) 22 | }, 23 | logoutUser () { 24 | return SecureEndpoint().post('/moqui-workflow/security/user/logout') 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/services/StatusFlowService.js: -------------------------------------------------------------------------------- 1 | import SecureEndpoint from '@/services/SecureEndpoint' 2 | 3 | export default { 4 | statusFlows (payload) { 5 | return SecureEndpoint().get('/moqui-workflow/basic/status/flow', { 6 | params: payload 7 | }) 8 | }, 9 | statusFlowItems (payload) { 10 | return SecureEndpoint().get('/moqui-workflow/basic/status/flow/' + payload.statusFlowId + '/item', { 11 | params: payload 12 | }) 13 | }, 14 | statusFlowTransitions (payload) { 15 | return SecureEndpoint().get('/moqui-workflow/basic/status/flow/' + payload.statusFlowId + '/transition', { 16 | params: payload 17 | }) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/services/UomService.js: -------------------------------------------------------------------------------- 1 | import SecureEndpoint from '@/services/SecureEndpoint' 2 | 3 | export default { 4 | uom (payload) { 5 | return SecureEndpoint().get('/moqui-workflow/basic/uom', { 6 | params: payload 7 | }) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/services/WorkflowService.js: -------------------------------------------------------------------------------- 1 | import SecureEndpoint from '@/services/SecureEndpoint' 2 | 3 | export default { 4 | workflows (payload) { 5 | return SecureEndpoint().get('/moqui-workflow/workflow', { 6 | params: payload 7 | }) 8 | }, 9 | createWorkflow (payload) { 10 | return SecureEndpoint().post('/moqui-workflow/workflow', payload) 11 | }, 12 | modifyWorkflow (payload) { 13 | return SecureEndpoint().patch('/moqui-workflow/workflow', payload) 14 | }, 15 | designWorkflow (payload) { 16 | return SecureEndpoint().post('/moqui-workflow/workflow/' + payload.workflowId + '/design', payload) 17 | }, 18 | workflowVariables (payload) { 19 | return SecureEndpoint().get('/moqui-workflow/workflow/' + payload.workflowId + '/variable', { 20 | params: payload 21 | }) 22 | }, 23 | createWorkflowVariable (payload) { 24 | return SecureEndpoint().post('/moqui-workflow/workflow/' + payload.workflowId + '/variable', payload) 25 | }, 26 | workflowInitiators (payload) { 27 | return SecureEndpoint().get('/moqui-workflow/workflow/' + payload.workflowId + '/initiator', { 28 | params: payload 29 | }) 30 | }, 31 | createWorkflowInitiator (payload) { 32 | return SecureEndpoint().post('/moqui-workflow/workflow/' + payload.workflowId + '/initiator', payload) 33 | }, 34 | expireWorkflowInitiator (payload) { 35 | return SecureEndpoint().delete('/moqui-workflow/workflow/' + payload.workflowId + '/initiator', { 36 | params: payload 37 | }) 38 | }, 39 | workflowTasks (payload) { 40 | return SecureEndpoint().get('/moqui-workflow/workflow/task', { 41 | params: payload 42 | }) 43 | }, 44 | countWorkflowTasks (payload) { 45 | return SecureEndpoint().get('/moqui-workflow/workflow/task/count', { 46 | params: payload 47 | }) 48 | }, 49 | modifyWorkflowTask (payload) { 50 | return SecureEndpoint().patch('/moqui-workflow/workflow/task', payload) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/services/WorkflowTypeService.js: -------------------------------------------------------------------------------- 1 | import SecureEndpoint from '@/services/SecureEndpoint' 2 | 3 | export default { 4 | workflowTypes (payload) { 5 | return SecureEndpoint().get('/moqui-workflow/workflowType', { 6 | params: payload 7 | }) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/shapes/AdjustmentActivity.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | let AdjustmentActivity = draw2d.shape.layout.VerticalLayout.extend({ 3 | 4 | /** 5 | * Shape name. 6 | */ 7 | NAME: "AdjustmentActivity", 8 | 9 | /** 10 | * Configuration defaults. 11 | */ 12 | DEFAULTS: { 13 | activityIcon: "\uf303", 14 | activityName: "Adjustment", 15 | activityNotDescribed: "No description provided", 16 | bgColor: "#ffffff", 17 | borderColor: "#6c757d", 18 | primaryColor: "#6c757d", 19 | secondaryColor: "#545454" 20 | }, 21 | 22 | /** 23 | * Initializes the shape. 24 | */ 25 | init: function (attr) { 26 | 27 | // init super 28 | let self = this; 29 | this._super($.extend({ 30 | bgColor: this.DEFAULTS.bgColor, 31 | color: this.DEFAULTS.borderColor, 32 | stroke: 2, 33 | padding: 5, 34 | radius: 10 35 | }, attr)); 36 | 37 | // init user data 38 | this.userData = { 39 | adjustmentTypeEnumId: 'WF_ADJUST_STATUS', 40 | statusId: '', 41 | statusDescription: '', 42 | variableId: '', 43 | variableName: '', 44 | definedValue: '', 45 | }; 46 | 47 | // activity icon 48 | this.activityIcon = new draw2d.shape.basic.Label({ 49 | text: this.DEFAULTS.activityIcon, 50 | cssClass: "workflow-activity-icon", 51 | fontColor: this.DEFAULTS.primaryColor, 52 | fontSize: 13, 53 | stroke: 0, 54 | padding: {top: 6, left: 0, right: 0, bottom: 0}, 55 | bold: true 56 | }); 57 | this.activityIcon.on("dblclick", function (emitter, event) { 58 | self.fireEvent("dblclick", {emitter: self, event: event}) 59 | }); 60 | 61 | // activity name 62 | this.activityName = new draw2d.shape.basic.Label({ 63 | text: this.DEFAULTS.activityName, 64 | cssClass: "workflow-activity-text", 65 | fontColor: this.DEFAULTS.primaryColor, 66 | fontSize: 13, 67 | stroke: 0, 68 | bold: true 69 | }); 70 | this.activityName.on("dblclick", function (emitter, event) { 71 | self.fireEvent("dblclick", {emitter: self, event: event}) 72 | }); 73 | 74 | // activity description 75 | this.activityDescription = new draw2d.shape.basic.Label({ 76 | text: this.DEFAULTS.activityNotDescribed, 77 | cssClass: "workflow-activity-text", 78 | fontColor: this.DEFAULTS.secondaryColor, 79 | fontSize: 12, 80 | padding: 5, 81 | stroke: 0 82 | }); 83 | this.activityDescription.on("dblclick", function (emitter, event) { 84 | self.fireEvent("dblclick", {emitter: self, event: event}) 85 | }); 86 | 87 | // header 88 | let header = new draw2d.shape.layout.HorizontalLayout({ 89 | }); 90 | header.on("dblclick", function (emitter, event) { 91 | self.fireEvent("dblclick", {emitter: self, event: event}) 92 | }); 93 | header.add(this.activityIcon) 94 | header.add(this.activityName) 95 | 96 | // footer 97 | let footer = new draw2d.shape.layout.HorizontalLayout({ 98 | }); 99 | footer.on("dblclick", function (emitter, event) { 100 | self.fireEvent("dblclick", {emitter: self, event: event}) 101 | }); 102 | footer.add(this.activityDescription); 103 | 104 | // add elements 105 | this.add(header); 106 | this.add(footer); 107 | 108 | // add ports 109 | this.addPorts(); 110 | }, 111 | 112 | /** 113 | * Add shape ports. 114 | */ 115 | addPorts: function (object) { 116 | 117 | // input port 118 | let inputPort = this.createPort("input", new draw2d.layout.locator.InputPortLocator()); 119 | inputPort.setBackgroundColor("#FFFFFF"); 120 | inputPort.setName("INPUT"); 121 | inputPort.setMaxFanOut(20); 122 | 123 | // success port 124 | let successPort = this.createPort("output", new draw2d.layout.locator.OutputPortLocator()); 125 | successPort.setBackgroundColor("#18F300"); 126 | successPort.setName("SUCCESS"); 127 | successPort.setMaxFanOut(20); 128 | 129 | // failure port 130 | let failurePort = this.createPort("output", new draw2d.layout.locator.OutputPortLocator()); 131 | failurePort.setBackgroundColor("#F30000"); 132 | failurePort.setName("FAILURE"); 133 | failurePort.setMaxFanOut(20); 134 | }, 135 | 136 | /** 137 | * Attach data to the shape. 138 | */ 139 | setUserData: function (object) { 140 | this._super(object); 141 | 142 | if (this.userData.activityDescription === '') { 143 | this.activityDescription.setText(this.DEFAULTS.activityNotDescribed); 144 | } else { 145 | this.activityDescription.setText(this.userData.activityDescription); 146 | } 147 | } 148 | }); 149 | 150 | window.AdjustmentActivity = AdjustmentActivity; 151 | -------------------------------------------------------------------------------- /src/shapes/ConditionActivity.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | let ConditionActivity = draw2d.shape.basic.Diamond.extend({ 3 | 4 | /** 5 | * Shape name. 6 | */ 7 | NAME: "ConditionActivity", 8 | 9 | /** 10 | * Configuration defaults. 11 | */ 12 | DEFAULTS: { 13 | activityName: "Condition", 14 | bgColor: "#ffffff", 15 | borderColor: "#745af2", 16 | primaryColor: "#745af2" 17 | }, 18 | 19 | /** 20 | * Initializes the shape. 21 | */ 22 | init: function (attr) { 23 | 24 | // init super 25 | let self = this; 26 | this._super($.extend({ 27 | bgColor: this.DEFAULTS.bgColor, 28 | color: this.DEFAULTS.borderColor, 29 | width: 110, 30 | height: 110, 31 | stroke: 2, 32 | padding: 5, 33 | radius: 4 34 | }, attr)); 35 | 36 | // init user data 37 | this.userData = { 38 | conditionTypeEnumId: 'WF_CONDITION_FIELD', 39 | joinOperator: 'AND', 40 | conditions: [] 41 | }; 42 | 43 | // activity name 44 | this.activityName = new draw2d.shape.basic.Label({ 45 | text: this.DEFAULTS.activityName, 46 | cssClass: "workflow-activity-text text-center", 47 | fontColor: this.DEFAULTS.primaryColor, 48 | fontSize: 13, 49 | stroke: 0, 50 | bold: true 51 | }); 52 | this.activityName.on("dblclick", function (emitter, event) { 53 | self.fireEvent("dblclick", {emitter: self, event: event}) 54 | }); 55 | 56 | // edit policy 57 | this.installEditPolicy(new draw2d.policy.figure.AntSelectionFeedbackPolicy()); 58 | 59 | // add elements 60 | this.add(this.activityName, new draw2d.layout.locator.CenterLocator()) 61 | 62 | // add ports 63 | this.addPorts(); 64 | }, 65 | 66 | /** 67 | * Add shape ports. 68 | */ 69 | addPorts: function (object) { 70 | 71 | // input port 72 | let inputPort = this.createPort("input", new draw2d.layout.locator.InputPortLocator()); 73 | inputPort.setBackgroundColor("#FFFFFF"); 74 | inputPort.setName("INPUT"); 75 | inputPort.setMaxFanOut(20); 76 | 77 | // success port 78 | let successPort = this.createPort("output", new draw2d.layout.locator.OutputPortLocator()); 79 | successPort.setBackgroundColor("#18F300"); 80 | successPort.setName("SUCCESS"); 81 | successPort.setMaxFanOut(20); 82 | 83 | // failure port 84 | let failurePort = this.createPort("output", new draw2d.layout.locator.BottomLocator()); 85 | failurePort.setBackgroundColor("#F30000"); 86 | failurePort.setName("FAILURE"); 87 | failurePort.setMaxFanOut(20); 88 | }, 89 | 90 | /** 91 | * Attach data to the shape. 92 | */ 93 | setUserData: function (object) { 94 | this._super(object); 95 | 96 | this.activityName.setText("Condition (" + this.userData.conditions.length + ")"); 97 | } 98 | }); 99 | 100 | window.ConditionActivity = ConditionActivity; 101 | -------------------------------------------------------------------------------- /src/shapes/EnterActivity.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | let EnterActivity = draw2d.shape.layout.VerticalLayout.extend({ 3 | 4 | /** 5 | * Shape name. 6 | */ 7 | NAME: "EnterActivity", 8 | 9 | /** 10 | * Configuration defaults. 11 | */ 12 | DEFAULTS: { 13 | activityIcon: "\uf144", 14 | activityName: "Enter", 15 | bgColor: "#82b54b", 16 | borderColor: "#648c3a", 17 | primaryColor: "#ffffff" 18 | }, 19 | 20 | /** 21 | * Initializes the shape. 22 | */ 23 | init: function (attr) { 24 | 25 | // init super 26 | let self = this; 27 | this._super($.extend({ 28 | bgColor: this.DEFAULTS.bgColor, 29 | color: this.DEFAULTS.borderColor, 30 | stroke: 2, 31 | padding: 5, 32 | radius: 10 33 | }, attr)); 34 | 35 | // init user data 36 | this.userData = { 37 | resultCode: 0 38 | }; 39 | 40 | // activity icon 41 | this.activityIcon = new draw2d.shape.basic.Label({ 42 | text: this.DEFAULTS.activityIcon, 43 | cssClass: "workflow-activity-icon", 44 | fontColor: this.DEFAULTS.primaryColor, 45 | fontSize: 13, 46 | padding: {top: 6, left: 0, right: 0, bottom: 0}, 47 | stroke: 0, 48 | bold: true 49 | }); 50 | 51 | // activity name 52 | this.activityName = new draw2d.shape.basic.Label({ 53 | text: this.DEFAULTS.activityName, 54 | cssClass: "workflow-activity-text", 55 | fontColor: this.DEFAULTS.primaryColor, 56 | fontSize: 13, 57 | stroke: 0, 58 | bold: true 59 | }); 60 | 61 | // header 62 | let header = new draw2d.shape.layout.HorizontalLayout({ 63 | }); 64 | header.add(this.activityIcon) 65 | header.add(this.activityName) 66 | 67 | // add elements 68 | this.add(header); 69 | 70 | // add ports 71 | this.addPorts(); 72 | }, 73 | 74 | /** 75 | * Add shape ports. 76 | */ 77 | addPorts: function (object) { 78 | 79 | // success port 80 | let successPort = this.createPort("output", new draw2d.layout.locator.OutputPortLocator()); 81 | successPort.setBackgroundColor("#18F300"); 82 | successPort.setName("SUCCESS"); 83 | successPort.setMaxFanOut(20); 84 | }, 85 | 86 | /** 87 | * Attach data to the shape. 88 | */ 89 | setUserData: function (object) { 90 | this._super(object); 91 | } 92 | }); 93 | 94 | window.EnterActivity = EnterActivity; 95 | -------------------------------------------------------------------------------- /src/shapes/ExitActivity.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | let ExitActivity = draw2d.shape.layout.VerticalLayout.extend({ 3 | 4 | /** 5 | * Shape name. 6 | */ 7 | NAME: "ExitActivity", 8 | 9 | /** 10 | * Configuration defaults. 11 | */ 12 | DEFAULTS: { 13 | activityIcon: "\uf28d", 14 | activityName: "Exit", 15 | bgColor: "#e04f1a", 16 | borderColor: "#b84115", 17 | primaryColor: "#ffffff" 18 | }, 19 | 20 | /** 21 | * Initializes the shape. 22 | */ 23 | init: function (attr) { 24 | 25 | // init super 26 | let self = this; 27 | this._super($.extend({ 28 | bgColor: this.DEFAULTS.bgColor, 29 | color: this.DEFAULTS.borderColor, 30 | stroke: 2, 31 | padding: 5, 32 | radius: 10 33 | }, attr)); 34 | 35 | // init user data 36 | this.userData = { 37 | resultCode: 0 38 | }; 39 | 40 | // activity icon 41 | this.activityIcon = new draw2d.shape.basic.Label({ 42 | text: this.DEFAULTS.activityIcon, 43 | cssClass: "workflow-activity-icon", 44 | fontColor: this.DEFAULTS.primaryColor, 45 | fontSize: 13, 46 | padding: {top: 6, left: 0, right: 0, bottom: 0}, 47 | stroke: 0, 48 | bold: true 49 | }); 50 | this.activityIcon.on("dblclick", function (emitter, event) { 51 | self.fireEvent("dblclick", {emitter: self, event: event}) 52 | }); 53 | 54 | // activity name 55 | this.activityName = new draw2d.shape.basic.Label({ 56 | text: this.DEFAULTS.activityName, 57 | cssClass: "workflow-activity-text", 58 | fontColor: this.DEFAULTS.primaryColor, 59 | fontSize: 13, 60 | stroke: 0, 61 | bold: true 62 | }); 63 | this.activityName.on("dblclick", function (emitter, event) { 64 | self.fireEvent("dblclick", {emitter: self, event: event}) 65 | }); 66 | 67 | // header 68 | let header = new draw2d.shape.layout.HorizontalLayout({ 69 | }); 70 | header.on("dblclick", function (emitter, event) { 71 | self.fireEvent("dblclick", {emitter: self, event: event}) 72 | }); 73 | header.add(this.activityIcon) 74 | header.add(this.activityName) 75 | 76 | // add elements 77 | this.add(header); 78 | 79 | // add ports 80 | this.addPorts(); 81 | }, 82 | 83 | /** 84 | * Add shape ports. 85 | */ 86 | addPorts: function (object) { 87 | 88 | // input port 89 | let inputPort = this.createPort("input", new draw2d.layout.locator.InputPortLocator()); 90 | inputPort.setBackgroundColor("#FFFFFF"); 91 | inputPort.setName("INPUT"); 92 | inputPort.setMaxFanOut(20); 93 | }, 94 | 95 | /** 96 | * Attach data to the shape. 97 | */ 98 | setUserData: function (object) { 99 | this._super(object); 100 | 101 | this.activityName.setText(this.DEFAULTS.activityName + " (" + this.userData.resultCode + ")"); 102 | } 103 | }); 104 | 105 | window.ExitActivity = ExitActivity; 106 | -------------------------------------------------------------------------------- /src/shapes/NotificationActivity.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | let NotificationActivity = draw2d.shape.layout.VerticalLayout.extend({ 3 | 4 | /** 5 | * Shape name. 6 | */ 7 | NAME: "NotificationActivity", 8 | 9 | /** 10 | * Configuration defaults. 11 | */ 12 | DEFAULTS: { 13 | activityIcon: "\uf0f3", 14 | activityName: "Notification", 15 | activityNotDescribed: "No description provided", 16 | bgColor: "#ffffff", 17 | borderColor: "#ffb119", 18 | primaryColor: "#ffb119", 19 | secondaryColor: "#545454" 20 | }, 21 | 22 | /** 23 | * Initializes the shape. 24 | */ 25 | init: function (attr) { 26 | 27 | // init super 28 | let self = this; 29 | this._super($.extend({ 30 | bgColor: this.DEFAULTS.bgColor, 31 | color: this.DEFAULTS.borderColor, 32 | stroke: 2, 33 | padding: 5, 34 | radius: 10 35 | }, attr)); 36 | 37 | // init user data 38 | this.userData = { 39 | activityDescription: '', 40 | notificationTypeEnumId: 'WF_NOTIFY_EMAIL', 41 | crowds: [], 42 | message: '' 43 | }; 44 | 45 | // activity icon 46 | this.activityIcon = new draw2d.shape.basic.Label({ 47 | text: this.DEFAULTS.activityIcon, 48 | cssClass: "workflow-activity-icon", 49 | fontColor: this.DEFAULTS.primaryColor, 50 | fontSize: 13, 51 | stroke: 0, 52 | padding: {top: 6, left: 0, right: 0, bottom: 0}, 53 | bold: true 54 | }); 55 | this.activityIcon.on("dblclick", function (emitter, event) { 56 | self.fireEvent("dblclick", {emitter: self, event: event}) 57 | }); 58 | 59 | // activity name 60 | this.activityName = new draw2d.shape.basic.Label({ 61 | text: this.DEFAULTS.activityName, 62 | cssClass: "workflow-activity-text", 63 | fontColor: this.DEFAULTS.primaryColor, 64 | fontSize: 13, 65 | stroke: 0, 66 | bold: true 67 | }); 68 | this.activityName.on("dblclick", function (emitter, event) { 69 | self.fireEvent("dblclick", {emitter: self, event: event}) 70 | }); 71 | 72 | // activity description 73 | this.activityDescription = new draw2d.shape.basic.Label({ 74 | text: this.DEFAULTS.activityNotDescribed, 75 | cssClass: "workflow-activity-text", 76 | fontColor: this.DEFAULTS.secondaryColor, 77 | fontSize: 12, 78 | padding: 5, 79 | stroke: 0 80 | }); 81 | this.activityDescription.on("dblclick", function (emitter, event) { 82 | self.fireEvent("dblclick", {emitter: self, event: event}) 83 | }); 84 | 85 | // header 86 | let header = new draw2d.shape.layout.HorizontalLayout({ 87 | }); 88 | header.on("dblclick", function (emitter, event) { 89 | self.fireEvent("dblclick", {emitter: self, event: event}) 90 | }); 91 | header.add(this.activityIcon) 92 | header.add(this.activityName) 93 | 94 | // footer 95 | let footer = new draw2d.shape.layout.HorizontalLayout({ 96 | }); 97 | footer.on("dblclick", function (emitter, event) { 98 | self.fireEvent("dblclick", {emitter: self, event: event}) 99 | }); 100 | footer.add(this.activityDescription); 101 | 102 | // add elements 103 | this.add(header); 104 | this.add(footer); 105 | 106 | // add ports 107 | this.addPorts(); 108 | }, 109 | 110 | /** 111 | * Add shape ports. 112 | */ 113 | addPorts: function (object) { 114 | 115 | // input port 116 | let inputPort = this.createPort("input", new draw2d.layout.locator.InputPortLocator()); 117 | inputPort.setBackgroundColor("#FFFFFF"); 118 | inputPort.setName("INPUT"); 119 | inputPort.setMaxFanOut(20); 120 | 121 | // success port 122 | let successPort = this.createPort("output", new draw2d.layout.locator.OutputPortLocator()); 123 | successPort.setBackgroundColor("#18F300"); 124 | successPort.setName("SUCCESS"); 125 | successPort.setMaxFanOut(20); 126 | 127 | // failure port 128 | let failurePort = this.createPort("output", new draw2d.layout.locator.OutputPortLocator()); 129 | failurePort.setBackgroundColor("#F30000"); 130 | failurePort.setName("FAILURE"); 131 | failurePort.setMaxFanOut(20); 132 | }, 133 | 134 | /** 135 | * Attach data to the shape. 136 | */ 137 | setUserData: function (object) { 138 | this._super(object); 139 | 140 | if (this.userData.activityDescription === '') { 141 | this.activityDescription.setText(this.DEFAULTS.activityNotDescribed); 142 | } else { 143 | this.activityDescription.setText(this.userData.activityDescription); 144 | } 145 | } 146 | }); 147 | 148 | window.NotificationActivity = NotificationActivity; 149 | -------------------------------------------------------------------------------- /src/shapes/ServiceActivity.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | let ServiceActivity = draw2d.shape.layout.VerticalLayout.extend({ 3 | 4 | /** 5 | * Shape name. 6 | */ 7 | NAME: "ServiceActivity", 8 | 9 | /** 10 | * Configuration defaults. 11 | */ 12 | DEFAULTS: { 13 | activityIcon: "\uf013", 14 | activityName: "Service", 15 | activityNotDescribed: "No description provided", 16 | bgColor: "#ffffff", 17 | borderColor: "#82b54b", 18 | primaryColor: "#82b54b", 19 | secondaryColor: "#545454" 20 | }, 21 | 22 | /** 23 | * Initializes the shape. 24 | */ 25 | init: function (attr) { 26 | 27 | // init super 28 | let self = this; 29 | this._super($.extend({ 30 | bgColor: this.DEFAULTS.bgColor, 31 | color: this.DEFAULTS.borderColor, 32 | stroke: 2, 33 | padding: 5, 34 | radius: 10 35 | }, attr)); 36 | 37 | // init user data 38 | this.userData = { 39 | serviceName: '', 40 | parameters: '' 41 | }; 42 | 43 | // activity icon 44 | this.activityIcon = new draw2d.shape.basic.Label({ 45 | text: this.DEFAULTS.activityIcon, 46 | cssClass: "workflow-activity-icon", 47 | fontColor: this.DEFAULTS.primaryColor, 48 | fontSize: 13, 49 | padding: {top: 6, left: 0, right: 0, bottom: 0}, 50 | stroke: 0, 51 | bold: true 52 | }); 53 | this.activityIcon.on("dblclick", function (emitter, event) { 54 | self.fireEvent("dblclick", {emitter: self, event: event}) 55 | }); 56 | 57 | // activity name 58 | this.activityName = new draw2d.shape.basic.Label({ 59 | text: this.DEFAULTS.activityName, 60 | cssClass: "workflow-activity-text", 61 | fontColor: this.DEFAULTS.primaryColor, 62 | fontSize: 13, 63 | stroke: 0, 64 | bold: true 65 | }); 66 | this.activityName.on("dblclick", function (emitter, event) { 67 | self.fireEvent("dblclick", {emitter: self, event: event}) 68 | }); 69 | 70 | // activity description 71 | this.activityDescription = new draw2d.shape.basic.Label({ 72 | text: this.DEFAULTS.activityNotDescribed, 73 | cssClass: "workflow-activity-text", 74 | fontColor: this.DEFAULTS.secondaryColor, 75 | fontSize: 12, 76 | padding: 5, 77 | stroke: 0 78 | }); 79 | this.activityDescription.on("dblclick", function (emitter, event) { 80 | self.fireEvent("dblclick", {emitter: self, event: event}) 81 | }); 82 | 83 | // header 84 | let header = new draw2d.shape.layout.HorizontalLayout({ 85 | }); 86 | header.on("dblclick", function (emitter, event) { 87 | self.fireEvent("dblclick", {emitter: self, event: event}) 88 | }); 89 | header.add(this.activityIcon) 90 | header.add(this.activityName) 91 | 92 | // footer 93 | let footer = new draw2d.shape.layout.HorizontalLayout({ 94 | }); 95 | footer.on("dblclick", function (emitter, event) { 96 | self.fireEvent("dblclick", {emitter: self, event: event}) 97 | }); 98 | footer.add(this.activityDescription); 99 | 100 | // add elements 101 | this.add(header); 102 | this.add(footer); 103 | 104 | // add ports 105 | this.addPorts(); 106 | }, 107 | 108 | /** 109 | * Add shape ports. 110 | */ 111 | addPorts: function (object) { 112 | 113 | // input port 114 | let inputPort = this.createPort("input", new draw2d.layout.locator.InputPortLocator()); 115 | inputPort.setBackgroundColor("#FFFFFF"); 116 | inputPort.setName("INPUT"); 117 | inputPort.setMaxFanOut(20); 118 | 119 | // success port 120 | let successPort = this.createPort("output", new draw2d.layout.locator.OutputPortLocator()); 121 | successPort.setBackgroundColor("#18F300"); 122 | successPort.setName("SUCCESS"); 123 | successPort.setMaxFanOut(20); 124 | 125 | // failure port 126 | let failurePort = this.createPort("output", new draw2d.layout.locator.OutputPortLocator()); 127 | failurePort.setBackgroundColor("#F30000"); 128 | failurePort.setName("FAILURE"); 129 | failurePort.setMaxFanOut(20); 130 | }, 131 | 132 | /** 133 | * Attach data to the shape. 134 | */ 135 | setUserData: function (object) { 136 | this._super(object); 137 | 138 | if (this.userData.activityDescription === '') { 139 | this.activityDescription.setText(this.DEFAULTS.activityNotDescribed); 140 | } else { 141 | this.activityDescription.setText(this.userData.activityDescription); 142 | } 143 | } 144 | }); 145 | 146 | window.ServiceActivity = ServiceActivity; 147 | -------------------------------------------------------------------------------- /src/shapes/UserActivity.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | let UserActivity = draw2d.shape.layout.VerticalLayout.extend({ 3 | 4 | /** 5 | * Shape name. 6 | */ 7 | NAME: "UserActivity", 8 | 9 | /** 10 | * Configuration defaults. 11 | */ 12 | DEFAULTS: { 13 | activityIcon: "\uf2bd", 14 | activityName: "User", 15 | activityNotDescribed: "No description provided", 16 | bgColor: "#ffffff", 17 | borderColor: "#212c43", 18 | primaryColor: "#212c43", 19 | secondaryColor: "#545454" 20 | }, 21 | 22 | /** 23 | * Initializes the shape. 24 | */ 25 | init: function (attr) { 26 | 27 | // init super 28 | let self = this; 29 | this._super($.extend({ 30 | bgColor: this.DEFAULTS.bgColor, 31 | color: this.DEFAULTS.borderColor, 32 | stroke: 2, 33 | padding: 5, 34 | radius: 10 35 | }, attr)); 36 | 37 | // init user data 38 | this.userData = { 39 | taskTypeEnumId: 'WF_TASK_APPROVAL', 40 | joinOperator: 'AND', 41 | crowds: [], 42 | timeoutInterval: 0, 43 | timeoutUomId: 'TF_wk', 44 | summary: '', 45 | description: '' 46 | }; 47 | 48 | // activity icon 49 | this.activityIcon = new draw2d.shape.basic.Label({ 50 | text: this.DEFAULTS.activityIcon, 51 | cssClass: "workflow-activity-icon", 52 | fontColor: this.DEFAULTS.primaryColor, 53 | fontSize: 13, 54 | padding: {top: 6, left: 0, right: 0, bottom: 0}, 55 | stroke: 0, 56 | bold: true 57 | }); 58 | this.activityIcon.on("dblclick", function (emitter, event) { 59 | self.fireEvent("dblclick", {emitter: self, event: event}) 60 | }); 61 | 62 | // activity name 63 | this.activityName = new draw2d.shape.basic.Label({ 64 | text: this.DEFAULTS.activityName, 65 | cssClass: "workflow-activity-text", 66 | fontColor: this.DEFAULTS.primaryColor, 67 | fontSize: 13, 68 | stroke: 0, 69 | bold: true 70 | }); 71 | this.activityName.on("dblclick", function (emitter, event) { 72 | self.fireEvent("dblclick", {emitter: self, event: event}) 73 | }); 74 | 75 | // activity description 76 | this.activityDescription = new draw2d.shape.basic.Label({ 77 | text: this.DEFAULTS.activityNotDescribed, 78 | cssClass: "workflow-activity-text", 79 | fontColor: this.DEFAULTS.secondaryColor, 80 | fontSize: 12, 81 | padding: 5, 82 | stroke: 0 83 | }); 84 | this.activityDescription.on("dblclick", function (emitter, event) { 85 | self.fireEvent("dblclick", {emitter: self, event: event}) 86 | }); 87 | 88 | // header 89 | let header = new draw2d.shape.layout.HorizontalLayout({ 90 | }); 91 | header.on("dblclick", function (emitter, event) { 92 | self.fireEvent("dblclick", {emitter: self, event: event}) 93 | }); 94 | header.add(this.activityIcon) 95 | header.add(this.activityName) 96 | 97 | // footer 98 | let footer = new draw2d.shape.layout.HorizontalLayout({ 99 | }); 100 | footer.on("dblclick", function (emitter, event) { 101 | self.fireEvent("dblclick", {emitter: self, event: event}) 102 | }); 103 | footer.add(this.activityDescription); 104 | 105 | // add elements 106 | this.add(header); 107 | this.add(footer); 108 | 109 | // add ports 110 | this.addPorts(); 111 | }, 112 | 113 | /** 114 | * Add shape ports. 115 | */ 116 | addPorts: function (object) { 117 | 118 | // input port 119 | let inputPort = this.createPort("input", new draw2d.layout.locator.InputPortLocator()); 120 | inputPort.setBackgroundColor("#FFFFFF"); 121 | inputPort.setName("INPUT"); 122 | inputPort.setMaxFanOut(20); 123 | 124 | // success port 125 | let successPort = this.createPort("output", new draw2d.layout.locator.OutputPortLocator()); 126 | successPort.setBackgroundColor("#18F300"); 127 | successPort.setName("SUCCESS"); 128 | successPort.setMaxFanOut(20); 129 | 130 | // failure port 131 | let failurePort = this.createPort("output", new draw2d.layout.locator.OutputPortLocator()); 132 | failurePort.setBackgroundColor("#F30000"); 133 | failurePort.setName("FAILURE"); 134 | failurePort.setMaxFanOut(20); 135 | 136 | // timeout port 137 | let timeoutPort = this.createPort("output", new draw2d.layout.locator.BottomLocator()); 138 | timeoutPort.setBackgroundColor("#FFA500"); 139 | timeoutPort.setName("TIMEOUT"); 140 | timeoutPort.setMaxFanOut(20); 141 | }, 142 | 143 | /** 144 | * Attach data to the shape. 145 | */ 146 | setUserData: function (object) { 147 | this._super(object); 148 | 149 | if (this.userData.activityDescription === '') { 150 | this.activityDescription.setText(this.DEFAULTS.activityNotDescribed); 151 | } else { 152 | this.activityDescription.setText(this.userData.activityDescription); 153 | } 154 | } 155 | }); 156 | 157 | window.UserActivity = UserActivity; 158 | -------------------------------------------------------------------------------- /src/store.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | 4 | Vue.use(Vuex) 5 | 6 | const getInitialState = () => { 7 | return { 8 | appId: process.env.VUE_APP_ID, 9 | language: 'en', 10 | userId: null, 11 | userFullName: null, 12 | requestPath: null, 13 | apiKey: null, 14 | sessionToken: null, 15 | userAuthenticated: false 16 | } 17 | } 18 | 19 | export default new Vuex.Store({ 20 | state: getInitialState(), 21 | mutations: { 22 | setApiKey (state, apiKey) { 23 | state.apiKey = apiKey 24 | state.userAuthenticated = apiKey !== null 25 | }, 26 | setUserId (state, userId) { 27 | state.userId = userId 28 | }, 29 | setUserFullName (state, userFullName) { 30 | state.userFullName = userFullName 31 | }, 32 | setSessionToken (state, sessionToken) { 33 | state.sessionToken = sessionToken 34 | }, 35 | setRequestPath (state, requestPath) { 36 | state.requestPath = requestPath 37 | }, 38 | setLanguage (state, language) { 39 | state.language = language 40 | } 41 | }, 42 | actions: { 43 | setApiKey ({ commit }, payload) { 44 | commit('setApiKey', payload.apiKey) 45 | }, 46 | setUserId ({ commit }, payload) { 47 | commit('setUserId', payload.userId) 48 | }, 49 | setUserFullName ({ commit }, payload) { 50 | commit('setUserFullName', payload.userFullName) 51 | }, 52 | setSessionToken ({ commit }, payload) { 53 | commit('setSessionToken', payload.sessionToken) 54 | }, 55 | setRequestPath ({ commit }, payload) { 56 | commit('setRequestPath', payload.requestPath) 57 | }, 58 | setLanguage ({ commit }, payload) { 59 | commit('setLanguage', payload.language) 60 | }, 61 | resetState ({ commit }, payload) { 62 | const initialState = getInitialState() 63 | this.dispatch('setUserId', { 64 | userId: initialState.userId 65 | }) 66 | this.dispatch('setUserFullName', { 67 | userId: initialState.userFullName 68 | }) 69 | this.dispatch('setRequestPath', { 70 | userId: initialState.requestPath 71 | }) 72 | this.dispatch('setApiKey', { 73 | userId: initialState.apiKey 74 | }) 75 | this.dispatch('setSessionToken', { 76 | userId: initialState.sessionToken 77 | }) 78 | this.dispatch('setLanguage', { 79 | language: initialState.language 80 | }) 81 | } 82 | } 83 | }) 84 | -------------------------------------------------------------------------------- /tests/e2e/custom-assertions/elementCount.js: -------------------------------------------------------------------------------- 1 | // A custom Nightwatch assertion. 2 | // The assertion name is the filename. 3 | // Example usage: 4 | // 5 | // browser.assert.elementCount(selector, count) 6 | // 7 | // For more information on custom assertions see: 8 | // http://nightwatchjs.org/guide#writing-custom-assertions 9 | 10 | exports.assertion = function elementCount (selector, count) { 11 | this.message = `Testing if element <${selector}> has count: ${count}` 12 | this.expected = count 13 | this.pass = val => val === count 14 | this.value = res => res.value 15 | function evaluator (_selector) { 16 | return document.querySelectorAll(_selector).length 17 | } 18 | this.command = cb => this.api.execute(evaluator, [selector], cb) 19 | } 20 | -------------------------------------------------------------------------------- /tests/e2e/specs/test.js: -------------------------------------------------------------------------------- 1 | // For authoring Nightwatch tests, see 2 | // http://nightwatchjs.org/guide#usage 3 | 4 | module.exports = { 5 | 'default e2e tests': browser => { 6 | browser 7 | .url(process.env.VUE_DEV_SERVER_URL) 8 | .waitForElementVisible('#app', 5000) 9 | .assert.elementPresent('.hello') 10 | .assert.containsText('h1', 'Welcome to Your Vue.js App') 11 | .assert.elementCount('img', 1) 12 | .end() 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/unit/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | jest: true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /tests/unit/example.spec.js: -------------------------------------------------------------------------------- 1 | import { shallowMount } from '@vue/test-utils' 2 | import HelloWorld from '@/components/HelloWorld.vue' 3 | 4 | describe('HelloWorld.vue', () => { 5 | it('renders props.msg when passed', () => { 6 | const msg = 'new message' 7 | const wrapper = shallowMount(HelloWorld, { 8 | propsData: { msg } 9 | }) 10 | expect(wrapper.text()).toMatch(msg) 11 | }) 12 | }) 13 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | // Ref: https://cli.vuejs.org/config/#assetsdir 2 | 'use strict' 3 | const webpack = require('webpack') 4 | 5 | module.exports = { 6 | publicPath: process.env.NODE_ENV === 'production' ? process.env.VUE_APP_PRODUCTION_PATH : '/', 7 | runtimeCompiler: true, 8 | devServer: { 9 | port: 8081, 10 | overlay: { 11 | warnings: true, 12 | errors: true 13 | }, 14 | proxy: { 15 | // proxy all requests starting with /rest/s1 to localhost:8080 16 | '/rest/s1': { 17 | target: 'http://localhost:8080', 18 | ws: true, 19 | changeOrigin: true 20 | } 21 | } 22 | }, 23 | configureWebpack: { 24 | plugins: [ 25 | new webpack.ProvidePlugin({ 26 | $: 'jquery', 27 | jquery: 'jquery', 28 | 'window.jQuery': 'jquery', 29 | jQuery: 'jquery' 30 | }) 31 | ] 32 | } 33 | } 34 | --------------------------------------------------------------------------------