diff --git a/.editorconfig b/.editorconfig index e89330a..b585a76 100644 --- a/.editorconfig +++ b/.editorconfig @@ -4,7 +4,7 @@ root = true [*] charset = utf-8 indent_style = space -indent_size = 2 +indent_size = 4 insert_final_newline = true trim_trailing_whitespace = true diff --git a/.eslintrc.json b/.eslintrc.json index 6460edf..8817e96 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,51 +1,51 @@ { - "root": true, - "ignorePatterns": [ - "projects/**/*" - ], - "overrides": [ - { - "files": [ - "*.ts" - ], - "parserOptions": { - "project": [ - "tsconfig.json", - "e2e/tsconfig.json" - ], - "createDefaultProgram": true - }, - "extends": [ - "plugin:@angular-eslint/recommended", - "plugin:@angular-eslint/template/process-inline-templates" - ], - "rules": { - "@angular-eslint/directive-selector": [ - "error", - { - "type": "attribute", - "prefix": "nab", - "style": "camelCase" - } - ], - "@angular-eslint/component-selector": [ - "error", - { - "type": "element", - "prefix": "nab", - "style": "kebab-case" - } - ] - } - }, - { - "files": [ - "*.html" - ], - "extends": [ - "plugin:@angular-eslint/template/recommended" - ], - "rules": {} - } - ] + "root": true, + "ignorePatterns": [ + "projects/**/*" + ], + "overrides": [ + { + "files": [ + "*.ts" + ], + "parserOptions": { + "project": [ + "tsconfig.json", + "e2e/tsconfig.json" + ], + "createDefaultProgram": true + }, + "extends": [ + "plugin:@angular-eslint/recommended", + "plugin:@angular-eslint/template/process-inline-templates" + ], + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "nab", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "nab", + "style": "kebab-case" + } + ] + } + }, + { + "files": [ + "*.html" + ], + "extends": [ + "plugin:@angular-eslint/template/recommended" + ], + "rules": {} + } + ] } diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index d00a9b4..b24becf 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -2,80 +2,80 @@ name: "🐛 Bug Report" description: Create a report to help us improve title: "[BUG] " labels: - - bug - - unverified + - bug + - unverified body: - - id: description - type: textarea - attributes: - label: Current behaviour - description: A clear and concise description of what the bug is. - validations: - required: false - - id: steps - type: textarea - attributes: - label: Steps to reproduce - description: Steps to reproduce the behavior. - placeholder: | - 1. Go to '...' - 2. Click on '....' - 3. Scroll down to '....' - 4. See error - validations: - required: true - - id: expected - type: textarea - attributes: - label: Expected behaviour - description: A clear and concise description of what you expected to happen. - validations: - required: false - - id: os - type: dropdown - attributes: - label: OS - description: OS of device - options: - - Windows - - Linux - - MacOS - - Android - - iOS - - other - validations: - required: false - - id: browser - type: dropdown - attributes: - label: Browser - description: Used web browser - options: - - Chrome - - Firefox - - Safari - - Edge - - Opera - - Other Chrome/Chromium based - - Other - validations: - required: false - - id: version - type: dropdown - attributes: - label: App version - options: - - 1.0.0 - default: 0 - validations: - required: true - - id: additional - type: textarea - attributes: - label: Anything else? - description: | - Links? References? Screenshots? Anything that will give us more context about the issue you are encountering! + - id: description + type: textarea + attributes: + label: Current behaviour + description: A clear and concise description of what the bug is. + validations: + required: false + - id: steps + type: textarea + attributes: + label: Steps to reproduce + description: Steps to reproduce the behavior. + placeholder: | + 1. Go to '...' + 2. Click on '....' + 3. Scroll down to '....' + 4. See error + validations: + required: true + - id: expected + type: textarea + attributes: + label: Expected behaviour + description: A clear and concise description of what you expected to happen. + validations: + required: false + - id: os + type: dropdown + attributes: + label: OS + description: OS of device + options: + - Windows + - Linux + - MacOS + - Android + - iOS + - other + validations: + required: false + - id: browser + type: dropdown + attributes: + label: Browser + description: Used web browser + options: + - Chrome + - Firefox + - Safari + - Edge + - Opera + - Other Chrome/Chromium based + - Other + validations: + required: false + - id: version + type: dropdown + attributes: + label: App version + options: + - 1.0.0 + default: 0 + validations: + required: true + - id: additional + type: textarea + attributes: + label: Anything else? + description: | + Links? References? Screenshots? Anything that will give us more context about the issue you are encountering! - Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. - validations: - required: false + Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml index da1ee23..f253e9c 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yaml +++ b/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -2,37 +2,37 @@ name: "⬆️ Feature request" description: Suggest an idea for this project title: "[FEATURE] " labels: - - improvement - - new + - improvement + - new body: - - id: problem - type: textarea - attributes: - label: Is your feature request related to a problem? - description: A clear and concise description of what the problem is. Ex. I'm always frustrated when... - validations: - required: false - - id: solution - type: textarea - attributes: - label: Describe the solution you'd like - description: A clear and concise description of what you want to happen. - validations: - required: false - - id: alternative - type: textarea - attributes: - label: Describe alternatives you've considered - description: A clear and concise description of any alternative solutions or features you've considered. - validations: - required: false - - id: additional - type: textarea - attributes: - label: Anything else? - description: | - Links? References? Screenshots? Anything that will give us more context about the request. + - id: problem + type: textarea + attributes: + label: Is your feature request related to a problem? + description: A clear and concise description of what the problem is. Ex. I'm always frustrated when... + validations: + required: false + - id: solution + type: textarea + attributes: + label: Describe the solution you'd like + description: A clear and concise description of what you want to happen. + validations: + required: false + - id: alternative + type: textarea + attributes: + label: Describe alternatives you've considered + description: A clear and concise description of any alternative solutions or features you've considered. + validations: + required: false + - id: additional + type: textarea + attributes: + label: Anything else? + description: | + Links? References? Screenshots? Anything that will give us more context about the request. - Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. - validations: - required: false + Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. + validations: + required: false diff --git a/.github/workflows/master-build.yaml b/.github/workflows/master-build.yaml index 83c4048..399fc50 100644 --- a/.github/workflows/master-build.yaml +++ b/.github/workflows/master-build.yaml @@ -1,32 +1,31 @@ name: Master Build on: - push: - branches: [ master ] + push: + branches: [ master ] jobs: - build: - name: Build - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 + build: + name: Build and update doc + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: 18 - - run: npm i --legacy-peer-deps + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: 18 + - run: npm i --legacy-peer-deps - - name: Test - # run: npm run full-test - run: npm run lint && npm run build + - name: Test + run: npm run lint && npm run build - # - name: Edit Path - # run: | - # sed -i 's/SF:.*.src/SF:src/g' coverage/lcov.info - # sed -i 's/SF:.*.src/SF:src/g' coverage/lcov.info -# - name: SonarCloud scan -# uses: SonarSource/sonarcloud-github-action@master -# env: -# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -# SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} +# - name: Edit Path +# run: | +# sed -i 's/SF:.*.src/SF:src/g' coverage/lcov.info +# sed -i 's/SF:.*.src/SF:src/g' coverage/lcov.info +# - name: SonarCloud scan +# uses: SonarSource/sonarcloud-github-action@master +# env: +# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +# SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/.github/workflows/pr-build.yaml b/.github/workflows/pr-build.yaml index 91c33ff..352b5b8 100644 --- a/.github/workflows/pr-build.yaml +++ b/.github/workflows/pr-build.yaml @@ -1,40 +1,40 @@ name: PR Test Build on: - pull_request: - types: [ opened, synchronize, reopened ] + pull_request: + types: [ opened, synchronize, reopened ] jobs: - build: - name: Build and test - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 + build: + name: Build and test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: 18 - - run: npm i --legacy-peer-deps + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: 18 + - run: npm i --legacy-peer-deps - - name: Lint - run: npm run lint + - name: Lint + run: npm run lint - - name: Build - run: npm run build - -# - name: Check spelling -# run: npm run spell -# -# - name: Test -# run: npm run test +# - name: Check spelling +# run: npm run spell # -# - name: Edit Path -# run: | -# sed -i 's/SF:.*.src/SF:src/g' coverage/lcov.info -# sed -i 's/SF:.*.src/SF:src/g' coverage/lcov.info -# - name: SonarCloud scan -# uses: SonarSource/sonarcloud-github-action@master -# env: -# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -# SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} +# - name: Test +# run: npm run test + + - name: Build + run: npm run build + +# - name: Edit Path +# run: | +# sed -i 's/SF:.*.src/SF:src/g' coverage/lcov.info +# sed -i 's/SF:.*.src/SF:src/g' coverage/lcov.info +# - name: SonarCloud scan +# uses: SonarSource/sonarcloud-github-action@master +# env: +# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +# SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/.github/workflows/release-build.yaml b/.github/workflows/release-build.yaml index 9581342..d0d2e44 100644 --- a/.github/workflows/release-build.yaml +++ b/.github/workflows/release-build.yaml @@ -1,96 +1,105 @@ name: Publish a release on: - release: - types: [ published ] + release: + types: [ published ] jobs: - publish-docker: - name: Docker build image and publish - runs-on: ubuntu-latest - permissions: - contents: read - packages: write + publish-docker: + name: Docker build image and publish + runs-on: ubuntu-latest + permissions: + contents: read + packages: write - steps: - - name: Checkout repository - uses: actions/checkout@v4 + steps: + - name: Checkout repository + uses: actions/checkout@v4 - - name: Log in to Docker Hub - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_AUTH_TOKEN }} + - name: Log in to Docker Hub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_AUTH_TOKEN }} - - name: Read package.json - uses: zvonimirsun/read-package-version-actions@v2 - id: getVersion + - name: Read package.json + uses: zvonimirsun/read-package-version-actions@v2 + id: getVersion - - name: Push Version ${{ steps.getVersion.outputs.version }} - uses: docker/build-push-action@v5 - with: - push: true - tags: netgrif/application-builder:${{ steps.getVersion.outputs.version }} + - name: Push Version ${{ steps.getVersion.outputs.version }} + uses: docker/build-push-action@v5 + with: + push: true + tags: netgrif/application-builder:${{ steps.getVersion.outputs.version }} - - name: Push Latest - if: ${{ !contains(steps.getVersion.outputs.version, '-') }} - uses: docker/build-push-action@v5 - with: - push: true - tags: netgrif/application-builder:latest + - name: Push Latest + if: ${{ !contains(steps.getVersion.outputs.version, '-') }} + uses: docker/build-push-action@v5 + with: + push: true + tags: netgrif/application-builder:latest - - name: Push Next - if: ${{ contains(steps.getVersion.outputs.version, '-') }} - uses: docker/build-push-action@v5 - with: - push: true - tags: netgrif/application-builder:next + - name: Push Next + if: ${{ contains(steps.getVersion.outputs.version, '-') }} + uses: docker/build-push-action@v5 + with: + push: true + tags: netgrif/application-builder:next - publish-assets: - name: Upload Release Assets - runs-on: ubuntu-latest - permissions: - contents: write - packages: write - id-token: write - security-events: write - steps: - - uses: actions/checkout@v4 + publish-assets: + name: Upload Release Assets + runs-on: ubuntu-latest + permissions: + contents: write + packages: write + id-token: write + security-events: write + steps: + - uses: actions/checkout@v4 - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: 18 + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: 18 - - name: Read package.json - uses: zvonimirsun/read-package-version-actions@v2 - id: getVersion + - name: Read package.json + uses: zvonimirsun/read-package-version-actions@v2 + id: getVersion - - name: Build - run: | - npm i --legacy-peer-deps - npm run build + - name: Build + run: | + npm i --legacy-peer-deps + npm run build - - name: Build project - run: | - zip -r netgrif-application-builder-${{ steps.getVersion.outputs.version }}.zip dist/application-builder + - name: Build project + run: | + zip -r netgrif-application-builder-${{ steps.getVersion.outputs.version }}.zip dist/application-builder - - name: Upload binaries to release - uses: svenstaro/upload-release-action@v2 - with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - file: netgrif-application-builder-${{ steps.getVersion.outputs.version }}.zip - asset_name: netgrif-application-builder-${{ steps.getVersion.outputs.version }}.zip - tag: ${{ github.ref }} - overwrite: true + - name: Upload binaries to release + uses: svenstaro/upload-release-action@v2 + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + file: netgrif-application-builder-${{ steps.getVersion.outputs.version }}.zip + asset_name: netgrif-application-builder-${{ steps.getVersion.outputs.version }}.zip + tag: ${{ github.ref }} + overwrite: true - deploy: - name: Deploy on K3S cluster - runs-on: ubuntu-latest - needs: publish-docker - steps: - - name: Apply new release - uses: actions-hub/kubectl@master - env: - KUBE_CONFIG: ${{ secrets.KUBE_CONFIG }} - KUBE_CONTEXT: default-github-builder - with: - args: rollout restart deployment/netgrif-application-builder-${{ contains(steps.getVersion.outputs.version, '-') && 'uat' || 'prod' }}-dpl --namespace builder + deploy: + name: Deploy on K3S cluster + runs-on: ubuntu-latest + needs: publish-docker + permissions: + contents: read + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Read package.json + uses: zvonimirsun/read-package-version-actions@v2 + id: getVersion + + - name: Apply new release + uses: actions-hub/kubectl@master + env: + KUBE_CONFIG: ${{ secrets.KUBE_CONFIG }} + KUBE_CONTEXT: default-github-builder + with: + args: rollout restart deployment/netgrif-application-builder-${{ contains(steps.getVersion.outputs.version, '-') && 'uat' || 'prod' }}-dpl --namespace builder diff --git a/CHANGELOG.md b/CHANGELOG.md index fef5f56..6a613d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,33 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -Full Changelog: [https://github.com/netgrif/application-builder/commits/v1.0.0](https://github.com/netgrif/application-builder/commits/v1.0.0) +Full Changelog: [https://github.com/netgrif/application-builder/commits/v2.0.0](https://github.com/netgrif/application-builder/commits/v2.0.0) + +## [v2.0.0](https://github.com/netgrif/application-builder/releases/tag/v2.0.0) (2024-11-11) + +### Added + +- Select tool +- Pan & zoom +- Material icon picker +- petriflow-svg library integration +- Tags on transition and Petri net +- History + +### Changed + +- Angular 17 +- Simulation mode - data simulation +- Canvas - switch between ID and Title, turn on/off grid +- Unified master-detail component in all views +- Upgrade petriflow.js to v1.3.6 +- Replace default dialogs with material + +### Fixed + +- Action editor performance +- I18nString view performance +- Action indentation ## [v1.0.0](https://github.com/netgrif/application-builder/releases/tag/v1.0.0) (2023-12-11) diff --git a/Dockerfile b/Dockerfile index 7d0a031..0663690 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,12 +1,12 @@ FROM node:18 as build -MAINTAINER Netgrif +MAINTAINER NETGRIF WORKDIR /app COPY . . RUN npm install --legacy-peer-deps RUN npm run build FROM nginx:alpine -MAINTAINER Netgrif +MAINTAINER NETGRIF COPY default.nginx.conf /etc/nginx/conf.d/default.conf COPY --from=build /app/dist/application-builder/ /usr/share/nginx/html/ EXPOSE 80 diff --git a/README.md b/README.md index 873e394..214578c 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![License](https://img.shields.io/badge/license-NETGRIF%20Community%20License-green)](https://netgrif.com/license) [![Angular dependency](https://img.shields.io/github/package-json/dependency-version/netgrif/application-builder/@angular/core?color=red)](https://www.angular.io/) -[![Petriflow 1.0.1](https://img.shields.io/badge/Petriflow-1.0.1-0aa8ff)](https://petriflow.com) +[![Petriflow 1.0.1](https://img.shields.io/badge/Petriflow-1.0.4-0aa8ff)](https://petriflow.com) [![Docker Pulls](https://img.shields.io/docker/pulls/netgrif/application-builder)](https://hub.docker.com/r/netgrif/application-builder) [![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/netgrif/application-builder?display_name=tag&sort=semver)](https://github.com/netgrif/application-builder/releases) [![Master Build](https://github.com/netgrif/application-builder/actions/workflows/master-build.yaml/badge.svg)](https://github.com/netgrif/application-builder/actions/workflows/master-build.yaml) @@ -12,13 +12,13 @@ Netgrif Application Builder is an angular web application for implementing process-driven application in low-code language Petriflow. Petriflow processes can be run/interpreted in Netgrif Application Engine. -Live build: [https://builder.netgrif.com](https://builder.netgrif.com) +Live build: [https://builder.netgrif.cloud](https://builder.netgrif.cloud) Application Builder consists of several modules that helps with development of business processes, application's dataset, permission schema, and many more. Builder can be deployed as is directly from the release artifact or as a docker container. It doesn't save your work on any server. It works only in a browser. * Petriflow low-code language: [http://petriflow.com](https://petriflow.com) -* Netgrif Application Engine: [NAE repozitory](https://github.com/netgrif/application-engine), [NAE documentation](https://engine.netgrif.com) +* Netgrif Application Engine: [NAE repository](https://github.com/netgrif/application-engine), [NAE documentation](https://engine.netgrif.com) * Issue Tracker: [GitHub issues](https://github.com/netgrif/application-builder/issues) * License: [NETGRIF Community License](https://github.com/netgrif/application-builder/blob/master/LICENSE) diff --git a/angular.json b/angular.json index 1c56b84..93a5291 100644 --- a/angular.json +++ b/angular.json @@ -1,157 +1,168 @@ { - "$schema": "./node_modules/@angular/cli/lib/config/schema.json", - "version": 1, - "newProjectRoot": "projects", - "projects": { - "application-builder": { - "projectType": "application", - "schematics": { - "@schematics/angular:component": { - "style": "scss" - } - }, - "root": "", - "sourceRoot": "src", - "prefix": "nab", - "architect": { - "build": { - "builder": "@angular-devkit/build-angular:browser", - "options": { - "outputPath": "dist/application-builder", - "index": "src/index.html", - "main": "src/main.ts", - "polyfills": "src/polyfills.ts", - "tsConfig": "tsconfig.app.json", - "assets": [ - "src/env.template.js", - "src/favicon.ico", - "src/assets", - "src/.htaccess", - { - "glob": "**/*", - "input": "node_modules/monaco-editor", - "output": "assets/monaco-editor/" - } - ], - "styles": [ - "./node_modules/@angular/material/prebuilt-themes/pink-bluegrey.css", - "src/netgif-theme.scss", - "src/styles.scss" - ], - "scripts": [], - "vendorChunk": true, - "extractLicenses": false, - "buildOptimizer": false, - "sourceMap": true, - "optimization": false, - "namedChunks": true - }, - "configurations": { - "production": { - "fileReplacements": [ - { - "replace": "src/environments/environment.ts", - "with": "src/environments/environment.prod.ts" - } - ], - "optimization": true, - "outputHashing": "all", - "sourceMap": false, - "namedChunks": false, - "extractLicenses": true, - "vendorChunk": false, - "buildOptimizer": true, - "budgets": [ - { - "type": "initial", - "maximumWarning": "5mb", - "maximumError": "10mb" + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "application-builder": { + "projectType": "application", + "schematics": { + "@schematics/angular:component": { + "style": "scss" }, - { - "type": "anyComponentStyle", - "maximumWarning": "6kb", - "maximumError": "10kb" + "@schematics/angular:application": { + "strict": true } - ] - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - } - }, - "serve": { - "builder": "@angular-devkit/build-angular:dev-server", - "options": {}, - "configurations": { - "production": { - "browserTarget": "application-builder:build:production" - }, - "development": { - "browserTarget": "application-builder:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "builder": "@angular-devkit/build-angular:extract-i18n", - "options": { - "browserTarget": "application-builder:build" - } - }, - "test": { - "builder": "@angular-devkit/build-angular:karma", - "options": { - "main": "src/test.ts", - "polyfills": "src/polyfills.ts", - "tsConfig": "tsconfig.spec.json", - "karmaConfig": "karma.conf.js", - "assets": [ - "src/favicon.ico", - "src/assets" - ], - "styles": [ - "./node_modules/@angular/material/prebuilt-themes/pink-bluegrey.css", - "src/styles.scss" - ], - "scripts": [], - "codeCoverage": true - } - }, - "e2e": { - "builder": "@angular-devkit/build-angular:protractor", - "options": { - "protractorConfig": "e2e/protractor.conf.js" - }, - "configurations": { - "production": { - "devServerTarget": "application-builder:serve:production" }, - "development": { - "devServerTarget": "application-builder:serve:development" + "root": "", + "sourceRoot": "src", + "prefix": "nab", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:browser", + "options": { + "allowedCommonJsDependencies": [ + "moment", + "buffer", + "easymde", + "semver", + "rfdc" + ], + "outputPath": "dist/application-builder", + "index": "src/index.html", + "main": "src/main.ts", + "polyfills": [ + "zone.js" + ], + "tsConfig": "tsconfig.app.json", + "assets": [ + "src/env.template.js", + "src/favicon.ico", + "src/assets", + "src/.htaccess", + { + "glob": "**/*", + "input": "node_modules/monaco-editor/min", + "output": "./assets/monaco/min" + }, + { + "glob": "**/*", + "input": "node_modules/monaco-editor/min-maps", + "output": "./assets/monaco/min-maps" + } + ], + "styles": [ + "src/netgif-theme.scss", + "src/styles.scss" + ], + "scripts": [] + }, + "configurations": { + "production": { + "fileReplacements": [ + { + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.prod.ts" + } + ], + "optimization": true, + "outputHashing": "all", + "sourceMap": false, + "namedChunks": false, + "extractLicenses": true, + "vendorChunk": false, + "buildOptimizer": true, + "budgets": [ + { + "type": "initial", + "maximumWarning": "5mb", + "maximumError": "10mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "6kb", + "maximumError": "10kb" + } + ] + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + } + }, + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "options": {}, + "configurations": { + "production": { + "buildTarget": "application-builder:build:production" + }, + "development": { + "buildTarget": "application-builder:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "application-builder:build" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "src/test.ts", + "polyfills": [ + "zone.js" + ], + "tsConfig": "tsconfig.spec.json", + "karmaConfig": "karma.conf.js", + "assets": [ + "src/favicon.ico", + "src/assets" + ], + "styles": [ + "./node_modules/@angular/material/prebuilt-themes/pink-bluegrey.css", + "src/styles.scss" + ], + "scripts": [], + "codeCoverage": true + } + }, + "e2e": { + "builder": "@angular-devkit/build-angular:protractor", + "options": { + "protractorConfig": "e2e/protractor.conf.js" + }, + "configurations": { + "production": { + "devServerTarget": "application-builder:serve:production" + }, + "development": { + "devServerTarget": "application-builder:serve:development" + } + }, + "defaultConfiguration": "development" + }, + "lint": { + "builder": "@angular-eslint/builder:lint", + "options": { + "lintFilePatterns": [ + "src/**/*.ts", + "src/**/*.html" + ] + } + } } - }, - "defaultConfiguration": "development" - }, - "lint": { - "builder": "@angular-eslint/builder:lint", - "options": { - "lintFilePatterns": [ - "src/**/*.ts", - "src/**/*.html" - ] - } } - } + }, + "cli": { + "analytics": "b689845b-1590-4bc6-a365-06155d598a09", + "defaultCollection": "@angular-eslint/schematics" } - }, - "defaultProject": "application-builder", - "cli": { - "analytics": "b689845b-1590-4bc6-a365-06155d598a09", - "defaultCollection": "@angular-eslint/schematics" - } } diff --git a/nae.json b/nae.json index 2906a8a..8df959b 100644 --- a/nae.json +++ b/nae.json @@ -1,114 +1,114 @@ { - "$schema": "./node_modules/@netgrif/application-engine/src/schema/nae-schema.json", - "extends": "nae-default", - "providers": { - "auth": { - "address": "http://localhost:8080/api/", - "authentication": "Basic", - "endpoints": { - "login": "auth/login", - "logout": "auth/logout", - "signup": "auth/signup", - "verification": "auth/verify", - "verify": "auth/token/verify", - "invite": "auth/invite", - "reset": "auth/reset", - "recover": "/auth/recover" - }, - "sessionBearer": "X-Auth-Token" + "$schema": "./node_modules/@netgrif/application-engine/src/schema/nae-schema.json", + "extends": "nae-default", + "providers": { + "auth": { + "address": "http://localhost:8080/api/", + "authentication": "Basic", + "endpoints": { + "login": "auth/login", + "logout": "auth/logout", + "signup": "auth/signup", + "verification": "auth/verify", + "verify": "auth/token/verify", + "invite": "auth/invite", + "reset": "auth/reset", + "recover": "/auth/recover" + }, + "sessionBearer": "X-Auth-Token" + }, + "resources": [ + { + "name": "case", + "address": "http://localhost:8080/api/", + "format": "hal", + "openApi": "https://swagger.io" + }, + { + "name": "task", + "address": "http://localhost:8080/api/", + "format": "json" + }, + { + "name": "petrinet", + "address": "http://localhost:8080/api/", + "format": "json" + }, + { + "name": "user", + "address": "http://localhost:8080/api/", + "format": "json" + }, + { + "name": "dashboard", + "address": "http://localhost:8080/api/", + "format": "json" + } + ] }, - "resources": [ - { - "name": "case", - "address": "http://localhost:8080/api/", - "format": "hal", - "openApi": "https://swagger.io" - }, - { - "name": "task", - "address": "http://localhost:8080/api/", - "format": "json" - }, - { - "name": "petrinet", - "address": "http://localhost:8080/api/", - "format": "json" - }, - { - "name": "user", - "address": "http://localhost:8080/api/", - "format": "json" - }, - { - "name": "dashboard", - "address": "http://localhost:8080/api/", - "format": "json" - } - ] - }, - "views": { - }, - "theme": { - "name": "nab", - "pallets": { - "light": { - "primary": { - "50": "#e2eaf0", - "100": "#b7c9d9", - "200": "#87a6c0", - "300": "#5782a7", - "400": "#336794", - "500": "#0f4c81", - "600": "#0d4579", - "700": "#0b3c6e", - "800": "#083364", - "900": "#042451", - "A100": "#ffd180", - "A200": "#ffab40", - "A400": "#ff9100", - "A700": "#ff6d00", - "contrast": { - "light": [ - "300", - "400", - "500", - "600", - "700", - "800", - "900" - ], - "dark": [ - "50", - "100", - "200" - ] - } - } - } - } - }, - "services": { - "log": { - "level": "ALL", - "logWithDate": true, - "serializeExtraParams": true, - "includeLogLevel": true, - "publishers": [ - "console", - "localStorage" - ] + "views": { }, - "dataFields": { - "template": "material", - "appearance": "outline" + "theme": { + "name": "nab", + "pallets": { + "light": { + "primary": { + "50": "#e2eaf0", + "100": "#b7c9d9", + "200": "#87a6c0", + "300": "#5782a7", + "400": "#336794", + "500": "#0f4c81", + "600": "#0d4579", + "700": "#0b3c6e", + "800": "#083364", + "900": "#042451", + "A100": "#ffd180", + "A200": "#ffab40", + "A400": "#ff9100", + "A700": "#ff6d00", + "contrast": { + "light": [ + "300", + "400", + "500", + "600", + "700", + "800", + "900" + ], + "dark": [ + "50", + "100", + "200" + ] + } + } + } + } }, - "urls": { - "netgrif": "https://netgrif.com", - "bpmn2pn": "https://bpmn2pn.netgrif.cloud", - "engine": "https://demo.netgrif.com/", - "youtube": "https://www.youtube.com/channel/UCNfqgnjskMMpy7QvOOKhKgw", - "github": "https://github.com/netgrif", - "issues": "https://github.com/netgrif/application-builder/issues" + "services": { + "log": { + "level": "ALL", + "logWithDate": true, + "serializeExtraParams": true, + "includeLogLevel": true, + "publishers": [ + "console", + "localStorage" + ] + }, + "dataFields": { + "template": "material", + "appearance": "outline" + }, + "urls": { + "netgrif": "https://netgrif.com", + "bpmn2pn": "https://bpmn2pn.netgrif.cloud/bpmn2pn/", + "engine": "https://demo.netgrif.com/", + "youtube": "https://www.youtube.com/channel/UCNfqgnjskMMpy7QvOOKhKgw", + "github": "https://github.com/netgrif", + "issues": "https://github.com/netgrif/application-builder/issues" + } } - } } diff --git a/package.json b/package.json index 0ffae7a..9634962 100644 --- a/package.json +++ b/package.json @@ -1,133 +1,135 @@ { - "name": "@netgrif/application-builder", - "version": "1.0.1", - "description": "Netgrif Application Builder for building, configuring and modeling applications for Application Engine.", - "homepage": "https://builder.netgrif.com", - "license": "SEE LICENSE IN LICENSE FILE", - "repository": { - "type": "git", - "url": "https://github.com/netgrif/application-builder.git" - }, - "bugs": { - "url": "https://github.com/netgrif/application-builder/issues" - }, - "author": { - "name": "NETGRIF, s.r.o.", - "email": "oss@netgrif.com", - "url": "https://netgrif.com" - }, - "keywords": [ - "netgrif", - "application builder", - "nab", - "engine", - "builder", - "workflow engine", - "nae builder", - "petriflow" - ], - "scripts": { - "ng": "ng", - "start": "ng serve", - "build": "ng build --configuration production --aot=false --build-optimizer=false", - "test": "ng test", - "lint": "ng lint", - "spell": "cspell \"{docs/**/*,src/**/*.ts}\"", - "e2e": "ng e2e", - "full-test": "npm run lint && npm run spell && npm run test", - "builder:clean-dist": "rm -rf dist", - "ng-high-memory-start": "node --max_old_space_size=8000 ./node_modules/@angular/cli/bin/ng serve" - }, - "private": true, - "dependencies": { - "@angular-material-components/datetime-picker": "~7.0.1", - "@angular-material-components/moment-adapter": "~7.0.0", - "@angular/animations": "~13.3.11", - "@angular/cdk": "~13.3.9", - "@angular/common": "~13.3.11", - "@angular/compiler": "~13.3.11", - "@angular/core": "~13.3.11", - "@angular/flex-layout": "~13.0.0-beta.38", - "@angular/forms": "~13.3.11", - "@angular/material": "~13.3.9", - "@angular/material-moment-adapter": "~13.3.9", - "@angular/platform-browser": "~13.3.11", - "@angular/platform-browser-dynamic": "~13.3.11", - "@angular/router": "~13.3.11", - "@covalent/core": "~3.1.0", - "@covalent/highlight": "~3.1.0", - "@covalent/markdown": "~3.1.0", - "@covalent/text-editor": "~3.1.0", - "@mdi/angular-material": "^4.9.95", - "@mdi/font": "^6.5.95", - "@netgrif/components": "~6.1.0", - "@netgrif/components-core": "~6.1.0", - "@netgrif/petriflow": "1.3.5", - "@ngx-translate/core": "~13.0.0", - "@ngx-translate/http-loader": "~6.0.0", - "@swimlane/ngx-charts": "~20.1.0", - "@types/mousetrap": "1.6.3", - "angular-gridster2": "^8.4.2", - "angular-resizable-element": "~3.3.0", - "angular-resize-event": "~3.1.1", - "angular2-hotkeys": "~2.2.0", - "browserify": "~16.5.0", - "escape-string-regexp": "^4.0.0", - "flag-icons": "^6.1.1", - "hammerjs": "~2.0.8", - "marked": "~4.0.12", - "moment": "~2.24.0", - "monaco-editor": "^0.33.0", - "natural-orderby": "~2.0.3", - "ngx-dropzone": "^3.1.0", - "ngx-joyride": "~2.3.1", - "ngx-monaco-editor": "^12.0.0", - "ngx-quill": "~12.0.1", - "quill": "~1.3.7", - "rollup": "~1.31.1", - "rollup-plugin-node-resolve": "~5.2.0", - "rxjs": "~6.5.3", - "tslib": "^2.0.0", - "xml-formatter": "^2.6.0", - "zone.js": "~0.11.4" - }, - "devDependencies": { - "@angular-devkit/build-angular": "~13.3.9", - "@angular-eslint/builder": "13.1.0", - "@angular-eslint/eslint-plugin": "13.1.0", - "@angular-eslint/eslint-plugin-template": "13.1.0", - "@angular-eslint/schematics": "13.1.0", - "@angular-eslint/template-parser": "13.1.0", - "@angular/cli": "~13.3.9", - "@angular/compiler-cli": "~13.3.11", - "@angular/language-service": "~13.3.11", - "@types/jasmine": "~3.6.0", - "@types/jasminewd2": "~2.0.3", - "@types/moment": "~2.13.0", - "@types/node": "~12.12.29", - "@typescript-eslint/eslint-plugin": "5.11.0", - "@typescript-eslint/parser": "5.11.0", - "codelyzer": "^6.0.0", - "cspell": "~5.18.4", - "eslint": "^8.2.0", - "jasmine-core": "~3.6.0", - "jasmine-reporters": "^2.3.2", - "jasmine-spec-reporter": "~5.0.0", - "karma": "~6.4.0", - "karma-chrome-launcher": "~3.1.0", - "karma-coverage-istanbul-reporter": "~2.1.0", - "karma-firefox-launcher": "~1.3.0", - "karma-jasmine": "~4.0.0", - "karma-jasmine-html-reporter": "^1.5.0", - "karma-junit-reporter": "~2.0.1", - "karma-mocha-reporter": "~2.2.5", - "karma-nyan-reporter": "~0.2.5", - "ng-packagr": "~13.3.1", - "protractor": "^7.0.0", - "puppeteer": "~2.1.1", - "sonarqube-scanner": "^2.8.0", - "ts-node": "~8.3.0", - "typescript": "~4.6.4", - "typescript-json-schema": "~0.42.0" - } + "name": "@netgrif/application-builder", + "version": "2.0.0", + "description": "Netgrif Application Builder for building, configuring and modeling applications for Application Engine.", + "homepage": "https://builder.netgrif.com", + "license": "SEE LICENSE IN LICENSE FILE", + "repository": { + "type": "git", + "url": "https://github.com/netgrif/application-builder.git" + }, + "bugs": { + "url": "https://github.com/netgrif/application-builder/issues" + }, + "author": { + "name": "NETGRIF, s.r.o.", + "email": "oss@netgrif.com", + "url": "https://netgrif.com" + }, + "keywords": [ + "netgrif", + "application builder", + "nab", + "engine", + "builder", + "workflow engine", + "nae builder", + "petriflow" + ], + "scripts": { + "ng": "ng", + "start": "ng serve", + "build": "ng build --configuration production --aot=false --build-optimizer=false", + "test": "ng test", + "lint": "ng lint", + "spell": "cspell \"{docs/**/*,**/*.md,src/**/*.ts}\"", + "e2e": "ng e2e", + "full-test": "npm run lint && npm run spell && npm run test", + "builder:clean-dist": "rm -rf dist", + "ng-high-memory-start": "node --max_old_space_size=8000 ./node_modules/@angular/cli/bin/ng serve" + }, + "private": true, + "dependencies": { + "@angular-material-components/datetime-picker": "~16.0.0", + "@angular-material-components/moment-adapter": "~16.0.0", + "@angular/animations": "~17.3.11", + "@angular/cdk": "~17.3.10", + "@angular/common": "~17.3.11", + "@angular/compiler": "~17.3.11", + "@angular/core": "~17.3.11", + "@angular/forms": "~17.3.11", + "@angular/material": "~17.3.10", + "@angular/material-moment-adapter": "~17.3.10", + "@angular/platform-browser": "~17.3.11", + "@angular/platform-browser-dynamic": "~17.3.11", + "@angular/router": "~17.3.11", + "@covalent/markdown": "~8.0.0", + "@mdi/angular-material": "^7.2.96", + "@mdi/font": "^7.4.47", + "@netgrif/components": "7.0.0-beta.1", + "@netgrif/components-core": "7.0.0-beta.1", + "@netgrif/petri.svg": "1.1.0", + "@netgrif/petriflow": "2.2.0", + "@netgrif/petriflow.svg": "1.1.0", + "@ngbracket/ngx-layout": "^17.0.1", + "@ngx-translate/core": "~15.0.0", + "@ngx-translate/http-loader": "~8.0.0", + "@panzoom/panzoom": "~4.5.1", + "@swimlane/ngx-charts": "~20.1.0", + "@types/mousetrap": "1.6.3", + "angular-gridster2": "^17.0.0", + "angular-resizable-element": "7.0.2", + "angular-resize-event": "3.2.0", + "browserify": "~16.5.0", + "easymde": "~2.16.1", + "escape-string-regexp": "^4.0.0", + "flag-icons": "^6.1.1", + "hammerjs": "~2.0.8", + "marked": "~4.0.12", + "moment": "~2.30.1", + "monaco-editor": "^0.44.0", + "natural-orderby": "~2.0.3", + "ngx-dropzone": "^3.1.0", + "ngx-joyride": "^2.5.0", + "ngx-monaco-editor-v2": "^17.0.1", + "ngx-quill": "~16.2.1", + "quill": "~1.3.7", + "rollup": "~1.31.1", + "rollup-plugin-node-resolve": "~5.2.0", + "rxjs": "~7.8.1", + "showdown": "^2.0.3", + "tslib": "^2.4.0", + "xml-formatter": "^3.6.2", + "zone.js": "~0.14.2", + "angular2-hotkeys": "~16.0.1" + }, + "devDependencies": { + "@angular-devkit/build-angular": "~17.3.8", + "@angular-eslint/builder": "17.2.1", + "@angular-eslint/eslint-plugin": "17.2.1", + "@angular-eslint/eslint-plugin-template": "17.2.1", + "@angular-eslint/schematics": "17.2.1", + "@angular-eslint/template-parser": "17.2.1", + "@angular/cli": "~17.3.8", + "@angular/compiler-cli": "~17.3.11", + "@angular/language-service": "~17.3.11", + "@types/jasmine": "~3.6.0", + "@types/jasminewd2": "~2.0.3", + "@types/moment": "~2.13.0", + "@types/node": "~12.12.29", + "@typescript-eslint/eslint-plugin": "8.13.0", + "@typescript-eslint/parser": "8.13.0", + "codelyzer": "^6.0.0", + "cspell": "~5.18.4", + "eslint": "^8.13.0", + "jasmine-core": "~3.6.0", + "jasmine-reporters": "^2.3.2", + "jasmine-spec-reporter": "~5.0.0", + "karma": "~6.4.0", + "karma-chrome-launcher": "~3.1.0", + "karma-coverage-istanbul-reporter": "~2.1.0", + "karma-firefox-launcher": "~1.3.0", + "karma-jasmine": "~4.0.0", + "karma-jasmine-html-reporter": "^1.5.0", + "karma-junit-reporter": "~2.0.1", + "karma-mocha-reporter": "~2.2.5", + "karma-nyan-reporter": "~0.2.5", + "ng-packagr": "~17.2.0", + "protractor": "^7.0.0", + "puppeteer": "~2.1.1", + "sonarqube-scanner": "^2.8.0", + "ts-node": "~8.3.0", + "typescript": "~5.3.3", + "typescript-json-schema": "~0.42.0" + } } diff --git a/src/app/app-builder-configuration.service.ts b/src/app/app-builder-configuration.service.ts index f26abdc..61130c7 100644 --- a/src/app/app-builder-configuration.service.ts +++ b/src/app/app-builder-configuration.service.ts @@ -3,26 +3,27 @@ import {ConfigurationService} from '@netgrif/components-core'; import {NetgrifApplicationEngine} from '@netgrif/components-core/'; import {default as naeConfig} from '../../nae.json'; + @Injectable({ - providedIn: 'root', + providedIn: 'root', }) export class AppBuilderConfigurationService extends ConfigurationService { - constructor() { - super(naeConfig as unknown as NetgrifApplicationEngine); - this.resolveConfigFromEnv(); - } + constructor() { + super(naeConfig as unknown as NetgrifApplicationEngine); + this.resolveConfigFromEnv(); + } - private resolveConfigFromEnv() { - if (!window['env']) return; - Object.keys(window['env']).forEach(key => { - const parts = key.split('-'); - let obj = this.configuration; - for (let i = 0; i < parts.length - 1; i++) { - obj = obj[parts[i]]; - } - if (!!window['env'][key] && window['env'][key] !== '') { - obj[parts[parts.length - 1]] = window['env'][key]; - } - }); - } + private resolveConfigFromEnv() { + if (!window['env']) return; + Object.keys(window['env']).forEach(key => { + const parts = key.split('-'); + let obj = this.configuration; + for (let i = 0; i < parts.length - 1; i++) { + obj = obj[parts[i]]; + } + if (!!window['env'][key] && window['env'][key] !== '') { + obj[parts[parts.length - 1]] = window['env'][key]; + } + }); + } } diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 7c98018..d1232dd 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -1,12 +1,12 @@ -import {NgModule} from '@angular/core'; +import { NgModule } from '@angular/core'; import {RouterModule, Routes} from '@angular/router'; import {CommonModule} from '@angular/common'; const routes: Routes = []; @NgModule({ - imports: [RouterModule.forRoot(routes, {relativeLinkResolution: 'legacy'})], - exports: [RouterModule, CommonModule], + imports: [RouterModule.forRoot(routes)], + exports: [RouterModule, CommonModule] }) export class AppRoutingModule { } diff --git a/src/app/app.component.html b/src/app/app.component.html index 6dd08fc..2ff3b60 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,54 +1,68 @@
- - - - - - - - - play_arrow - - - - - - - - - - device_hub - - - - - device_hub - - - - - - - help - - - - - - - + + + + + + play_arrow + + + + + + device_hub + + + device_hub + + + + + bug_report + + + help + + + + + +
diff --git a/src/app/app.component.scss b/src/app/app.component.scss index b47d847..ae422ac 100644 --- a/src/app/app.component.scss +++ b/src/app/app.component.scss @@ -1,69 +1,90 @@ .app-mat-sidenav-container { - height: 100%; + height: 100%; +} + +.main-toolbar-logo { + width: 35px; + height: 41px; } .app-mat-viewnav { - //background-color: map-get($netgrif-blue, 600); GLOBAL STYLE + display: flex; + flex-direction: column; + + .logo { + display: flex; + justify-content: center; + padding-top: 0; + } - mat-action-list { - overflow: hidden; - } + mat-action-list { + overflow: hidden; + } - .selected { - //border-left: map-get($netgrif-blue, A200); GLOBAL STYLE - border-left-style: solid; - //background-color: map-get($netgrif-blue, 700); GLOBAL STYLE + .selected { + //border-left: map-get($netgrif-blue, A200); GLOBAL STYLE + border-left-style: solid; + //background-color: map-get($netgrif-blue, 700); GLOBAL STYLE - mat-icon { - color: white; - margin-left: -3px; + mat-icon { + color: white; + margin-left: -3px; + } } - } - mat-icon { - //color: map-get($netgrif-blue, 200); GLOBAL STYLE - } + mat-icon { + //color: map-get($netgrif-blue, 200); GLOBAL STYLE + } } .app-container { - display: flex; - flex-direction: column; - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; + display: flex; + flex-direction: column; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; } .app-mat-icon { - margin: 10px; + margin: 10px; } .app-mat-toolbar { - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3); - z-index: 10; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3); + z-index: 10; } .mat-icon-button { - input[type="file"] { - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - opacity: 0; - cursor: pointer; - width: 100%; - } + input[type="file"] { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + opacity: 0; + cursor: pointer; + width: 100%; + } } .app-viewnaw-bottom-list { - position: absolute; - bottom: 0; + position: absolute; + bottom: 0; } .main-toolbar-logo img { - margin-top: 8px; - width: 40px; - border-radius: 20%; + margin-top: 8px; + width: 42px; + border-radius: 20%; +} + +.menu-items { + padding-top: 0; + .mdc-list-item { + padding-left: 9px; + padding-right: 9px; + height: 42px; + } } diff --git a/src/app/app.component.ts b/src/app/app.component.ts index b4b7522..693c837 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,59 +1,91 @@ -import {Component, HostListener} from '@angular/core'; +import {AfterViewInit, Component, HostListener} from '@angular/core'; import {MatDialog} from '@angular/material/dialog'; import {Router} from '@angular/router'; -import {LanguageService} from '@netgrif/components-core'; import {NetgrifApplicationEngine} from '@netgrif/components-core/'; -import {JoyrideService} from 'ngx-joyride'; import {AppBuilderConfigurationService} from './app-builder-configuration.service'; import {DialogConfirmComponent} from './dialogs/dialog-confirm/dialog-confirm.component'; +import { + DialogLocalStorageModelComponent, +} from './dialogs/dialog-local-storage-model/dialog-local-storage-model.component'; +import {ModelImportService} from './modeler/model-import-service'; +import {ModelerConfig} from './modeler/modeler-config'; import {MortgageService} from './modeler/mortgage.service'; +import {ModelService} from './modeler/services/model/model.service'; import {TutorialService} from './tutorial/tutorial-service'; +import {JoyrideService} from 'ngx-joyride'; @Component({ - selector: 'nab-root', - templateUrl: './app.component.html', - styleUrls: ['./app.component.scss'], + selector: 'nab-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.scss'], }) -export class AppComponent { - title = 'Netgrif Application Builder'; - config: NetgrifApplicationEngine; - - @HostListener('window:beforeunload', ['$event']) - WindowBeforeUnload($event: any) { - $event.returnValue = 'Your data will be lost!'; - } - - constructor( - config: AppBuilderConfigurationService, - private router: Router, - private _languageService: LanguageService, - private matDialog: MatDialog, - private readonly joyrideService: JoyrideService, - private _mortgageService: MortgageService, - private tutorialService: TutorialService, - ) { - this.config = config.get(); - } - - addMortgage() { - const dialogRef = this.matDialog.open(DialogConfirmComponent); - - dialogRef.afterClosed().subscribe(result => { - if (result === true) { - this._mortgageService.loadModel(); - this.router.navigate(['/modeler']); - } - }); - } - - help() { - this.joyrideService.startTour({ - steps: this.tutorialService.steps, - themeColor: '#0f4c81dd', - }); - } - - get tutorial() { - return this.tutorialService; - } +export class AppComponent implements AfterViewInit { + title = 'Netgrif Application Builder'; + config: NetgrifApplicationEngine; + + @HostListener('window:beforeunload', ['$event']) + WindowBeforeUnload($event: any) { + $event.returnValue = 'Your data will be lost!'; + } + + constructor( + config: AppBuilderConfigurationService, + private router: Router, + private matDialog: MatDialog, + private readonly joyrideService: JoyrideService, + private _mortgageService: MortgageService, + private tutorialService: TutorialService, + private modelService: ModelService, + private importService: ModelImportService, + ) { + this.config = config.get(); + } + + ngAfterViewInit(): void { + // TODO: NAB-326 https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API + const oldModel = localStorage.getItem(ModelerConfig.LOCALSTORAGE.DRAFT_MODEL.KEY); + if (!oldModel) { + return; + } + const dialogRef = this.matDialog.open(DialogLocalStorageModelComponent, { + data: { + id: localStorage.getItem(ModelerConfig.LOCALSTORAGE.DRAFT_MODEL.ID), + timestamp: localStorage.getItem(ModelerConfig.LOCALSTORAGE.DRAFT_MODEL.TIMESTAMP), + title: localStorage.getItem(ModelerConfig.LOCALSTORAGE.DRAFT_MODEL.TITLE), + }, + }); + dialogRef.afterClosed().subscribe(result => { + if (result === true) { + this.importService.importFromXml(oldModel); + } else if (result === false) { + localStorage.clear(); + } + }); + } + + addMortgage() { + const dialogRef = this.matDialog.open(DialogConfirmComponent); + + dialogRef.afterClosed().subscribe(result => { + if (result === true) { + this._mortgageService.loadModel(); + this.router.navigate(['/modeler']); + } + }); + } + + help() { + this.joyrideService.startTour({ + steps: this.tutorialService.steps, + themeColor: '#0f4c81dd', + }); + } + + get tutorial() { + return this.tutorialService; + } + + openInTab(url: string) { + window.open(url, '_blank'); + } } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 1fe4838..06daff8 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -2,7 +2,6 @@ import {BrowserModule, DomSanitizer} from '@angular/platform-browser'; import {NgModule} from '@angular/core'; import {AppComponent} from './app.component'; import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; -import {FlexLayoutModule} from '@angular/flex-layout'; import {MaterialImportModule} from './material-import/material-import.module'; import {FormBuilderModule} from './form-builder/form-builder.module'; import {RouterModule, Routes} from '@angular/router'; @@ -10,78 +9,105 @@ import {FormBuilderComponent} from './form-builder/form-builder.component'; import {ModelerComponent} from './modeler/modeler.component'; import {ModelerModule} from './modeler/modeler.module'; import {EditModeComponent} from './modeler/edit-mode/edit-mode.component'; -import {SimulationModeComponent} from './modeler/simulation-mode/simulation-mode.component'; import {DataModeComponent} from './modeler/data-mode/data-mode.component'; import {RoleModeComponent} from './modeler/role-mode/role-mode.component'; import {ActionsModeComponent} from './modeler/actions-mode/actions-mode.component'; import {MatIconRegistry} from '@angular/material/icon'; -import {AuthenticationModule, ConfigurationService, TranslateLibModule} from '@netgrif/components-core'; -import {AppBuilderConfigurationService} from './app-builder-configuration.service'; import {environment} from '../environments/environment'; import {DialogConfirmComponent} from './dialogs/dialog-confirm/dialog-confirm.component'; -import {JoyrideModule} from 'ngx-joyride'; import {DialogRefactorComponent} from './dialogs/dialog-refactor/dialog-refactor.component'; import {DialogErrorsComponent} from './dialogs/dialog-errors/dialog-errors.component'; -import {TaskContentComponentModule} from '@netgrif/components'; import {ExportService, ImportService} from '@netgrif/petriflow'; import {SelectedTransitionService} from './modeler/selected-transition.service'; import {I18nModeComponent} from './modeler/i18n-mode/i18n-mode.component'; import {DialogDeadNetComponent} from './dialogs/dialog-dead-net/dialog-dead-net.component'; import {AppRoutingModule} from './app-routing.module'; import {DialogPlaceRefDeleteComponent} from './dialogs/dialog-place-ref-delete/dialog-place-ref-delete.component'; +import {DialogPlaceEditComponent} from './dialogs/dialog-place-edit/dialog-place-edit.component'; +import {DialogDeleteModelComponent} from './dialogs/dialog-delete-model/dialog-delete-model.component'; +import {DialogArcEditComponent} from './dialogs/dialog-arc-edit/dialog-arc-edit.component'; +import {DialogTransitionEditComponent} from './dialogs/dialog-transition-edit/dialog-transition-edit.component'; +import {SimulationModeComponent} from './modeler/simulation-mode/simulation-mode.component'; +import { + DialogLocalStorageModelComponent +} from './dialogs/dialog-local-storage-model/dialog-local-storage-model.component'; +import {HistoryModeComponent} from './modeler/history-mode/history-mode.component'; +import {DialogChangeDataComponent} from './dialogs/dialog-change-data/dialog-change-data.component'; +import {DialogModelEditComponent} from './dialogs/dialog-model-edit/dialog-model-edit.component'; +import {MaterialIconPickerComponent} from './modeler/components/material-icon-picker/material-icon-picker.component'; +import {CommonModule, NgOptimizedImage} from '@angular/common'; +import {MAT_FORM_FIELD_DEFAULT_OPTIONS} from '@angular/material/form-field'; +import {TaskContentComponentModule} from '@netgrif/components'; +import {JoyrideModule} from 'ngx-joyride'; +import {AuthenticationMethodService, ConfigurationService, NullAuthenticationService} from '@netgrif/components-core'; +import {AppBuilderConfigurationService} from './app-builder-configuration.service'; +import {MatProgressSpinnerModule} from '@angular/material/progress-spinner'; +import {MatPaginatorIntl} from '@angular/material/paginator'; +import {BuilderPaginatorIntl} from './modeler/components/master-detail/main-master/builder-paginator-inpl'; const appRoutes: Routes = [ - { - path: 'modeler', component: ModelerComponent, children: [ - {path: '', component: EditModeComponent}, - {path: 'simulation', component: SimulationModeComponent}, - {path: 'data', component: DataModeComponent}, - {path: 'roles', component: RoleModeComponent}, - {path: 'actions', component: ActionsModeComponent}, - {path: 'i18n', component: I18nModeComponent}, - ], - }, - {path: 'form', component: FormBuilderComponent}, - {path: '**', redirectTo: 'modeler'}, + { + path: 'modeler', component: ModelerComponent, children: [ + {path: '', component: EditModeComponent}, + {path: SimulationModeComponent.URL, component: SimulationModeComponent}, + {path: 'data', component: DataModeComponent}, + {path: 'roles', component: RoleModeComponent}, + {path: 'actions', component: ActionsModeComponent}, + {path: 'i18n', component: I18nModeComponent}, + {path: 'history', component: HistoryModeComponent}, + ] + }, + {path: 'form', component: FormBuilderComponent}, + {path: '**', redirectTo: 'modeler'} ]; @NgModule({ - declarations: [ - AppComponent, - DialogConfirmComponent, - DialogRefactorComponent, - DialogErrorsComponent, - DialogDeadNetComponent, - DialogPlaceRefDeleteComponent, - ], - imports: [ - BrowserModule, - BrowserAnimationsModule, - MaterialImportModule, - FlexLayoutModule, - FormBuilderModule, - ModelerModule, - TranslateLibModule, - AuthenticationModule, - RouterModule.forRoot(appRoutes, {relativeLinkResolution: 'legacy'}), - JoyrideModule.forRoot(), - TaskContentComponentModule, - AppRoutingModule, - ], - providers: [ - ImportService, - ExportService, - {provide: ConfigurationService, useClass: AppBuilderConfigurationService}, - // {provide: MAT_FORM_FIELD_DEFAULT_OPTIONS, useValue: {appearance: MaterialAppearance.OUTLINE}} - ], - bootstrap: [AppComponent], + declarations: [ + AppComponent, + DialogConfirmComponent, + DialogRefactorComponent, + DialogErrorsComponent, + DialogDeadNetComponent, + DialogPlaceRefDeleteComponent, + DialogPlaceEditComponent, + DialogDeleteModelComponent, + DialogArcEditComponent, + DialogTransitionEditComponent, + DialogChangeDataComponent, + DialogModelEditComponent, + MaterialIconPickerComponent, + DialogLocalStorageModelComponent, + ], + imports: [ + BrowserModule, + BrowserAnimationsModule, + MaterialImportModule, + FormBuilderModule, + JoyrideModule.forRoot(), + ModelerModule, + RouterModule.forRoot(appRoutes), + AppRoutingModule, + NgOptimizedImage, + TaskContentComponentModule, + CommonModule, + MatProgressSpinnerModule + ], + providers: [ + ImportService, + ExportService, + {provide: MatPaginatorIntl, useClass: BuilderPaginatorIntl}, + {provide: AuthenticationMethodService, useValue: NullAuthenticationService}, + {provide: ConfigurationService, useClass: AppBuilderConfigurationService}, + {provide: MAT_FORM_FIELD_DEFAULT_OPTIONS, useValue: {appearance: 'outline'}} + ], + exports: [], + bootstrap: [AppComponent] }) export class AppModule { - - constructor(matIconRegistry: MatIconRegistry, domSanitizer: DomSanitizer, private transitionService: SelectedTransitionService) { - this.transitionService.id = undefined; - matIconRegistry.addSvgIcon('twitch', domSanitizer.bypassSecurityTrustResourceUrl(`../../..${environment.deployUrl}assets/twitch.svg`)); - matIconRegistry.addSvgIcon('youtube', domSanitizer.bypassSecurityTrustResourceUrl(`../../..${environment.deployUrl}assets/youtube.svg`)); - matIconRegistry.addSvgIcon('github', domSanitizer.bypassSecurityTrustResourceUrl(`../../..${environment.deployUrl}assets/github.svg`)); - } + constructor(matIconRegistry: MatIconRegistry, domSanitizer: DomSanitizer, private transitionService: SelectedTransitionService) { + this.transitionService.id = undefined; + matIconRegistry.addSvgIcon('twitch', domSanitizer.bypassSecurityTrustResourceUrl(`../../..${environment.deployUrl}assets/twitch.svg`)); + matIconRegistry.addSvgIcon('youtube', domSanitizer.bypassSecurityTrustResourceUrl(`../../..${environment.deployUrl}assets/youtube.svg`)); + matIconRegistry.addSvgIcon('github', domSanitizer.bypassSecurityTrustResourceUrl(`../../..${environment.deployUrl}assets/github.svg`)); + } } diff --git a/src/app/cdk-import/cdk-import.module.ts b/src/app/cdk-import/cdk-import.module.ts index c1b6dc1..7aa4037 100644 --- a/src/app/cdk-import/cdk-import.module.ts +++ b/src/app/cdk-import/cdk-import.module.ts @@ -1,11 +1,13 @@ import {NgModule} from '@angular/core'; import {CdkTreeModule} from '@angular/cdk/tree'; +import {CdkPortal, CdkPortalOutlet} from '@angular/cdk/portal'; @NgModule({ - declarations: [], - imports: [ - CdkTreeModule, - ], + declarations: [], + imports: [ + CdkPortalOutlet, + CdkTreeModule + ] }) export class CdkImportModule { } diff --git a/src/app/dialogs/dialog-add-language/dialog-add-language.component.html b/src/app/dialogs/dialog-add-language/dialog-add-language.component.html index 390277f..eea2201 100644 --- a/src/app/dialogs/dialog-add-language/dialog-add-language.component.html +++ b/src/app/dialogs/dialog-add-language/dialog-add-language.component.html @@ -1,6 +1,6 @@

Add language

- + Language diff --git a/src/app/dialogs/dialog-arc-attach/dialog-arc-attach.component.html b/src/app/dialogs/dialog-arc-attach/dialog-arc-attach.component.html index 947778a..f18c897 100644 --- a/src/app/dialogs/dialog-arc-attach/dialog-arc-attach.component.html +++ b/src/app/dialogs/dialog-arc-attach/dialog-arc-attach.component.html @@ -1,29 +1,29 @@

Referenced Datavariables

-
- -
-

Title

-

Id

-

Value

-

Reference

-

Actions

-
- -

{{ item.title?.value }}

-

{{ item.id }}

-

{{ item.init?.expression }}

-

{{ isSelected(item) ? 'Referenced' : '' }}

- - -
-
- - +
+ +
+

{{isData() ? 'Title' : 'Label'}}

+

Id

+

Value

+

Reference

+

Actions

+
+ +

{{isData() ? item.title?.value : item.label.value}}

+

{{item.id}}

+

{{isData() ? item.init?.expression : item.marking}}

+

{{isSelected(item) ? 'Referenced' : ''}}

+ + +
+
+ +
diff --git a/src/app/dialogs/dialog-arc-attach/dialog-arc-attach.component.ts b/src/app/dialogs/dialog-arc-attach/dialog-arc-attach.component.ts index 6702525..4e6fc8e 100644 --- a/src/app/dialogs/dialog-arc-attach/dialog-arc-attach.component.ts +++ b/src/app/dialogs/dialog-arc-attach/dialog-arc-attach.component.ts @@ -1,65 +1,79 @@ -import {Component} from '@angular/core'; -import {MatDialogRef} from '@angular/material/dialog'; -import {DataVariable} from '@netgrif/petriflow'; +import {Component, Inject} from '@angular/core'; +import {DataVariable, Place} from '@netgrif/petriflow'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {ModelerConfig} from '../../modeler/modeler-config'; -import {ModelService} from '../../modeler/services/model.service'; +import {ReferenceDialogData} from '../../modeler/edit-mode/domain/reference-dialog-data'; +import {ModelService} from '../../modeler/services/model/model.service'; @Component({ - selector: 'nab-dialog-arc-attach', - templateUrl: './dialog-arc-attach.component.html', - styleUrls: ['./dialog-arc-attach.component.scss'], + selector: 'nab-dialog-arc-attach', + templateUrl: './dialog-arc-attach.component.html', + styleUrls: ['./dialog-arc-attach.component.scss'] }) export class DialogArcAttachComponent { - dataSource: Array; - length: number; - pageSize: number; - pageIndex: number; - pageSizeOptions: Array = [10, 20, 50, 100]; - selectedItem: DataVariable; + dataSource: Array | Array; + length: number; + pageSize: number; + pageIndex: number; + pageSizeOptions: Array = [10, 20, 50]; + selectedItem: DataVariable | Place; - constructor(private modelService: ModelService, public dialogRef: MatDialogRef) { - this.pageSize = 20; - this.pageIndex = 0; - this.dataSource = this.modelService.model.getDataSet().filter(data => ModelerConfig.VARIABLE_ARC_DATA_TYPES.includes(data.type)); - this.length = this.dataSource.length; - if (this.modelService.graphicModel.arcForData.arc.reference) { - this.selectedItem = this.modelService.model.getData(this.modelService.graphicModel.arcForData.arc.reference); + constructor( + private modelService: ModelService, + public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: ReferenceDialogData + ) { + this.pageSize = 20; + this.pageIndex = 0; + if (data.dialogType === 'data') { + this.dataSource = this.modelService.model.getDataSet().filter(dataField => ModelerConfig.VARIABLE_ARC_DATA_TYPES.includes(dataField.type)); + } else { + this.dataSource = this.modelService.model.getPlaces(); + } + this.length = this.dataSource.length; + if (!!this.data.arcReference.reference) { + this.selectedItem = this.data.dialogType === 'data' ? this.modelService.model.getData(this.data.arcReference.reference) + : this.modelService.model.getPlace(this.data.arcReference.reference); + } + this.dialogRef.beforeClosed().subscribe(() => { + this.dialogRef.close(this.selectedItem); + }); } - this.dialogRef.beforeClosed().subscribe(() => { - this.dialogRef.close(this.selectedItem); - }); - } - onPageChanged(e) { - this.pageIndex = e.pageIndex; - this.pageSize = e.pageSize; - const firstCut = e.pageIndex * e.pageSize; - const secondCut = firstCut + e.pageSize; - this.dataSource = this.modelService.model.getDataSet().slice(firstCut, secondCut); - } + onPageChanged(e) { + this.pageIndex = e.pageIndex; + this.pageSize = e.pageSize; + const firstCut = e.pageIndex * e.pageSize; + const secondCut = firstCut + e.pageSize; + this.dataSource = this.modelService.model.getDataSet().slice(firstCut, secondCut); + } - setArcVariability(item: DataVariable) { - if (!item.init) { - alert('Empty init.'); - return; + setArcVariability(item: DataVariable | Place) { + if (item instanceof DataVariable && !item.init) { + alert('Empty init.'); + return; + } + const weight = item instanceof DataVariable ? parseInt(item.init.value, 10) : item.marking; + if (weight < 0) { + alert('A negative number. Cannot change the value of arc weight.'); + return; + } + this.selectedItem = item; } - const vaha = parseInt(item.init.value, 10); - if (vaha < 0) { - alert('A negative number. Cannot change the value of arc weight.'); - return; + + removeArcVariability() { + this.selectedItem = undefined; } - this.selectedItem = item; - } - removeArcVariability() { - this.selectedItem = undefined; - } + isSelected(item: DataVariable): boolean { + if (this.selectedItem !== undefined) { + return item.id === this.selectedItem.id; + } else { + return false; + } + } - isSelected(item: DataVariable): boolean { - if (this.selectedItem !== undefined) { - return item.id === this.selectedItem.id; - } else { - return false; + isData(): boolean { + return this.data.dialogType === 'data'; } - } } diff --git a/src/app/dialogs/dialog-arc-edit/changed-arc.ts b/src/app/dialogs/dialog-arc-edit/changed-arc.ts new file mode 100644 index 0000000..6946ce9 --- /dev/null +++ b/src/app/dialogs/dialog-arc-edit/changed-arc.ts @@ -0,0 +1,16 @@ +import {Arc, ArcType, NodeElement, PetriNet} from '@netgrif/petriflow'; + +export class ChangedArc { + + public readonly id: string; + public readonly arc: Arc; + public arcType: ArcType; + public readonly model: PetriNet; + + constructor(model: PetriNet, arc?: Arc, id = arc?.id) { + this.id = id; + this.arc = arc; + this.arcType = arc?.type; + this.model = model; + } +} diff --git a/src/app/dialogs/dialog-arc-edit/dialog-arc-edit.component.html b/src/app/dialogs/dialog-arc-edit/dialog-arc-edit.component.html new file mode 100644 index 0000000..efc2ccc --- /dev/null +++ b/src/app/dialogs/dialog-arc-edit/dialog-arc-edit.component.html @@ -0,0 +1,54 @@ +

Edit arc

+ + + Id + + + + Type + + + {{arcType}} + + + {{arcTypeIcons.get(arcType)}}{{arcType}} + + + + + Multiplicity + + Id is required + Multiplicity must be a positive integer + + + Reference + + + -- None -- + + + {{reference.label}} [{{reference.id}}] + + + + + + Source + + + + Destination + + + + + + diff --git a/src/app/dialogs/dialog-arc-edit/dialog-arc-edit.component.scss b/src/app/dialogs/dialog-arc-edit/dialog-arc-edit.component.scss new file mode 100644 index 0000000..3c26464 --- /dev/null +++ b/src/app/dialogs/dialog-arc-edit/dialog-arc-edit.component.scss @@ -0,0 +1,10 @@ +mat-dialog-content { + display: flex; + flex-direction: column; +} + +mat-dialog-actions { + display: flex; + justify-content: flex-end; +} + diff --git a/src/app/dialogs/dialog-arc-edit/dialog-arc-edit.component.ts b/src/app/dialogs/dialog-arc-edit/dialog-arc-edit.component.ts new file mode 100644 index 0000000..29ac420 --- /dev/null +++ b/src/app/dialogs/dialog-arc-edit/dialog-arc-edit.component.ts @@ -0,0 +1,134 @@ +import {Component, Inject, OnInit} from '@angular/core'; +import {ModelService} from '../../modeler/services/model/model.service'; +import {Arc, DataType, TransitionPlaceArc, XmlArcType} from '@netgrif/petriflow'; +import {MAT_DIALOG_DATA} from '@angular/material/dialog'; +import {ChangedArc} from './changed-arc'; +import {FormControl, ValidatorFn, Validators} from '@angular/forms'; +import {Observable} from 'rxjs'; +import {map, startWith} from 'rxjs/operators'; + +export interface ArcEditData { + arcId: string; +} + +export interface Reference { + id: string; + label: string; +} + +export interface ReferenceGroup { + name: string; + references: Array; +} + +@Component({ + selector: 'nab-dialog-arc-edit', + templateUrl: './dialog-arc-edit.component.html', + styleUrls: ['./dialog-arc-edit.component.scss'] +}) +export class DialogArcEditComponent implements OnInit { + + public arc: ChangedArc; + public arcType: XmlArcType; + public arcTypes: Array; + public references: Array; + public multiplicityCtrl: FormControl; + formControlRef: FormControl; + filteredReferences: Observable>; + + public arcTypeMapping = Arc.arcTypeMapping; + + public arcTypeIcons: Map = new Map([ + [XmlArcType.REGULAR, 'play_arrow'], + [XmlArcType.READ, 'circle'], + [XmlArcType.RESET, 'fast_forward'], + [XmlArcType.INHIBITOR, 'radio_button_unchecked'], + ]); + + constructor( + @Inject(MAT_DIALOG_DATA) public data: ArcEditData, + public modelService: ModelService + ) { + this.arc = new ChangedArc(undefined, this.modelService.model.getArc(data.arcId).clone()); + this.formControlRef = new FormControl(''); + this.multiplicityCtrl = new FormControl('', [ + Validators.required, + this.validMultiplicity() + ]); + } + + ngOnInit(): void { + this.arcTypes = Object.values(XmlArcType); + this.arcType = this.arcTypeMapping.get(this.arc.arcType); + this.references = []; + this.addReferences('Data fields', this.modelService.model.getDataSet() + .filter(data => data.type === DataType.NUMBER) + .map(data => { + return {id: data.id, label: data.title?.value} as Reference; + }) + .sort((a, b) => a.label?.localeCompare(b.label))); + this.addReferences('Places', this.modelService.model.getPlaces() + .map(place => { + return {id: place.id, label: place.label?.value} as Reference; + }) + .sort((a, b) => a.label?.localeCompare(b.label))); + this.filteredReferences = this.formControlRef.valueChanges.pipe( + startWith(''), + map(value => this._filter(value || '')), + ); + } + + private addReferences(name: string, references: Array): void { + if (references.length === 0) { + return; + } + this.references.push({name, references}); + } + + isTPArc(): boolean { + return this.arc.arc instanceof TransitionPlaceArc; + } + + onTypeChange(newValue: XmlArcType): void { + this.arc.arcType = this.modelService.toArcType(newValue); + } + + private _filter(value: string): Array { + const filterValue = value.toLowerCase(); + const groups = new Array(); + this.references.forEach(group => { + const startsWith = new Array(); + const includes = new Array(); + group.references.forEach(reference => { + if (reference.id?.includes(filterValue)) { + if (reference.id?.startsWith(filterValue)) { + startsWith.push(reference); + } else { + includes.push(reference); + } + } else if (reference.label?.includes(filterValue)) { + if (reference.label?.startsWith(filterValue)) { + startsWith.push(reference); + } else { + includes.push(reference); + } + } + }); + groups.push({ + name: group.name, + references: startsWith.concat(includes) + }); + }) + return groups; + } + + private validMultiplicity(): ValidatorFn { + return (fc: FormControl): { [key: string]: any } | null => { + const multiplicity = Math.floor(fc.value as number); + if (multiplicity !== Infinity && multiplicity === fc.value as number && multiplicity > 0) { + return null; + } + return ({validMultiplicity: true}) + }; + } +} diff --git a/src/app/dialogs/dialog-change-data/dialog-change-data.component.html b/src/app/dialogs/dialog-change-data/dialog-change-data.component.html new file mode 100644 index 0000000..74ff097 --- /dev/null +++ b/src/app/dialogs/dialog-change-data/dialog-change-data.component.html @@ -0,0 +1,14 @@ +

Change referenced data values

+ + + {{data.id}} + + + No referenced data found + + + + diff --git a/src/app/dialogs/dialog-change-data/dialog-change-data.component.scss b/src/app/dialogs/dialog-change-data/dialog-change-data.component.scss new file mode 100644 index 0000000..c667359 --- /dev/null +++ b/src/app/dialogs/dialog-change-data/dialog-change-data.component.scss @@ -0,0 +1,8 @@ +mat-dialog-content { + display: flex; + flex-direction: column; +} + +mat-dialog-actions { + justify-content: flex-end; +} diff --git a/src/app/dialogs/dialog-change-data/dialog-change-data.component.ts b/src/app/dialogs/dialog-change-data/dialog-change-data.component.ts new file mode 100644 index 0000000..4d2a21f --- /dev/null +++ b/src/app/dialogs/dialog-change-data/dialog-change-data.component.ts @@ -0,0 +1,28 @@ +import {Component, Inject, OnInit} from '@angular/core'; +import {MAT_DIALOG_DATA} from '@angular/material/dialog'; + +export interface DataSet { + dataSet: Map; +} + +export interface Data { + id: string, + value: number +} + +@Component({ + selector: 'nab-dialog-change-data', + templateUrl: './dialog-change-data.component.html', + styleUrls: ['./dialog-change-data.component.scss'] +}) +export class DialogChangeDataComponent { + + public dataSet: Array; + + constructor( + @Inject(MAT_DIALOG_DATA) public data: DataSet, + ) { + this.dataSet = new Array(); + data.dataSet.forEach((value, id) => this.dataSet.push({id, value})); + } +} diff --git a/src/app/dialogs/dialog-confirm/dialog-confirm.component.html b/src/app/dialogs/dialog-confirm/dialog-confirm.component.html index fd336c4..9b7f496 100644 --- a/src/app/dialogs/dialog-confirm/dialog-confirm.component.html +++ b/src/app/dialogs/dialog-confirm/dialog-confirm.component.html @@ -1,8 +1,8 @@

New Model Confirmation

-

Are you sure you want to open example model ? You loose data from actual model.

+ Are you sure you want to open example model ? You loose all data from actual model.
- - + + diff --git a/src/app/dialogs/dialog-dead-net/dialog-dead-net.component.html b/src/app/dialogs/dialog-dead-net/dialog-dead-net.component.html index 9dd7a4d..9397475 100644 --- a/src/app/dialogs/dialog-dead-net/dialog-dead-net.component.html +++ b/src/app/dialogs/dialog-dead-net/dialog-dead-net.component.html @@ -1,11 +1,8 @@ -

- warning_amber - No executable task -

+

No executable task

-

There are no executable tasks. Are you sure you want to download the model ?

+ There are no executable tasks. Are you sure you want to download the model ?
- - + + diff --git a/src/app/dialogs/dialog-dead-net/dialog-dead-net.component.scss b/src/app/dialogs/dialog-dead-net/dialog-dead-net.component.scss index 99aba5d..e69de29 100644 --- a/src/app/dialogs/dialog-dead-net/dialog-dead-net.component.scss +++ b/src/app/dialogs/dialog-dead-net/dialog-dead-net.component.scss @@ -1,10 +0,0 @@ -h2 { - vertical-align: top; - display: inline-flex; - align-items: center; -} - -mat-icon { - padding-right: 5px; - color: darkgoldenrod; -} diff --git a/src/app/dialogs/dialog-delete-model/dialog-delete-model.component.html b/src/app/dialogs/dialog-delete-model/dialog-delete-model.component.html new file mode 100644 index 0000000..bb7e5b4 --- /dev/null +++ b/src/app/dialogs/dialog-delete-model/dialog-delete-model.component.html @@ -0,0 +1,11 @@ +

+ warning_amber + Delete model +

+ +

Are you sure to delete the model? Any unsaved changes will be lost.

+
+ + + + diff --git a/src/app/dialogs/dialog-delete-model/dialog-delete-model.component.scss b/src/app/dialogs/dialog-delete-model/dialog-delete-model.component.scss new file mode 100644 index 0000000..5064b61 --- /dev/null +++ b/src/app/dialogs/dialog-delete-model/dialog-delete-model.component.scss @@ -0,0 +1,10 @@ +h2 { + vertical-align: top; + display: inline-flex; + align-items: center; +} + +mat-icon { + padding-right: 5px; + color: darkgoldenrod; +} diff --git a/src/app/dialogs/dialog-delete-model/dialog-delete-model.component.spec.ts b/src/app/dialogs/dialog-delete-model/dialog-delete-model.component.spec.ts new file mode 100644 index 0000000..5924233 --- /dev/null +++ b/src/app/dialogs/dialog-delete-model/dialog-delete-model.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { DialogDeleteModelComponent } from './dialog-delete-model.component'; + +describe('DialogDeleteModelComponent', () => { + let component: DialogDeleteModelComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ DialogDeleteModelComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(DialogDeleteModelComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/dialogs/dialog-delete-model/dialog-delete-model.component.ts b/src/app/dialogs/dialog-delete-model/dialog-delete-model.component.ts new file mode 100644 index 0000000..b624604 --- /dev/null +++ b/src/app/dialogs/dialog-delete-model/dialog-delete-model.component.ts @@ -0,0 +1,11 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'nab-dialog-delete-model', + templateUrl: './dialog-delete-model.component.html', + styleUrls: ['./dialog-delete-model.component.scss'] +}) +export class DialogDeleteModelComponent { + + constructor() { } +} diff --git a/src/app/dialogs/dialog-errors/dialog-errors.component.ts b/src/app/dialogs/dialog-errors/dialog-errors.component.ts index 9b65611..5186f44 100644 --- a/src/app/dialogs/dialog-errors/dialog-errors.component.ts +++ b/src/app/dialogs/dialog-errors/dialog-errors.component.ts @@ -1,20 +1,19 @@ -import {Component, Inject} from '@angular/core'; +import {Component, Inject, OnInit} from '@angular/core'; import {MAT_DIALOG_DATA} from '@angular/material/dialog'; export interface DialogErrorsData { - errors: Array; - warnings: Array; - info: Array; + errors: Array; + warnings: Array; + info: Array; } @Component({ - selector: 'nab-dialog-errors', - templateUrl: './dialog-errors.component.html', - styleUrls: ['./dialog-errors.component.scss'], + selector: 'nab-dialog-errors', + templateUrl: './dialog-errors.component.html', + styleUrls: ['./dialog-errors.component.scss'] }) export class DialogErrorsComponent { - constructor(@Inject(MAT_DIALOG_DATA) public data: DialogErrorsData) { - } - + constructor(@Inject(MAT_DIALOG_DATA) public data: DialogErrorsData) { + } } diff --git a/src/app/dialogs/dialog-local-storage-model/dialog-local-storage-model.component.html b/src/app/dialogs/dialog-local-storage-model/dialog-local-storage-model.component.html new file mode 100644 index 0000000..21e2693 --- /dev/null +++ b/src/app/dialogs/dialog-local-storage-model/dialog-local-storage-model.component.html @@ -0,0 +1,14 @@ +

Continue previous work

+ + Do you wish to continue work on "{{data.title}}" [{{data.id}}] from {{data.timestamp}} + + + + + diff --git a/src/app/dialogs/dialog-local-storage-model/dialog-local-storage-model.component.scss b/src/app/dialogs/dialog-local-storage-model/dialog-local-storage-model.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/dialogs/dialog-local-storage-model/dialog-local-storage-model.component.spec.ts b/src/app/dialogs/dialog-local-storage-model/dialog-local-storage-model.component.spec.ts new file mode 100644 index 0000000..c5dc7bd --- /dev/null +++ b/src/app/dialogs/dialog-local-storage-model/dialog-local-storage-model.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { DialogLocalStorageModelComponent } from './dialog-local-storage-model.component'; + +describe('DialogLocalStorageModelComponent', () => { + let component: DialogLocalStorageModelComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ DialogLocalStorageModelComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(DialogLocalStorageModelComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/dialogs/dialog-local-storage-model/dialog-local-storage-model.component.ts b/src/app/dialogs/dialog-local-storage-model/dialog-local-storage-model.component.ts new file mode 100644 index 0000000..093bf7f --- /dev/null +++ b/src/app/dialogs/dialog-local-storage-model/dialog-local-storage-model.component.ts @@ -0,0 +1,22 @@ +import {Component, Inject, OnInit} from '@angular/core'; +import {MAT_DIALOG_DATA} from '@angular/material/dialog'; + +export interface DialogData { + id: string; + timestamp: string; + title: string; +} + +@Component({ + selector: 'nab-dialog-local-storage-model', + templateUrl: './dialog-local-storage-model.component.html', + styleUrls: ['./dialog-local-storage-model.component.scss'] +}) +export class DialogLocalStorageModelComponent { + + constructor( + @Inject(MAT_DIALOG_DATA) public data: DialogData + ) { + } + +} diff --git a/src/app/dialogs/dialog-manage-roles/dialog-manage-roles.component.html b/src/app/dialogs/dialog-manage-roles/dialog-manage-roles.component.html index 99e7d74..2c5b2ef 100644 --- a/src/app/dialogs/dialog-manage-roles/dialog-manage-roles.component.html +++ b/src/app/dialogs/dialog-manage-roles/dialog-manage-roles.component.html @@ -1,295 +1,295 @@ -

{{ data.type === 'transition' ? 'Transition' : 'Process' }} Permissions

+

{{data.type === 'transition' ? 'Transition' : 'Process'}} Permissions

-
Role Permissions - - +
Role Permissions +
+ - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - -
Id - {{ element.id }} Id + {{element.id}} - Perform - - - {{ stringValue(element.logic.perform) }} - - + Perform + + + {{stringValue(element.logic.perform) | titlecase}} + + - Delegate - - - {{ stringValue(element.logic.delegate) }} - - + Delegate + + + {{stringValue(element.logic.delegate) | titlecase}} + + - Cancel - - - {{ stringValue(element.logic.cancel) }} - - + Cancel + + + {{stringValue(element.logic.cancel) | titlecase}} + + - Assign - - - {{ stringValue(element.logic.assign) }} - - + Assign + + + {{stringValue(element.logic.assign) | titlecase}} + + - View - - - {{ stringValue(element.logic.view) }} - - + View + + + {{stringValue(element.logic.view) | titlecase}} + + - Create - - - {{ stringValue(element.caseLogic.create) }} - - + Create + + + {{stringValue(element.logic.create) | titlecase}} + + - Delete - - - {{ stringValue(element.caseLogic.delete) }} - - + Delete + + + {{stringValue(element.logic.delete) | titlecase}} + + View - - - {{ stringValue(element.caseLogic.view) }} - - View + + + {{stringValue(element.logic.view) | titlecase}} + +
+ + + - -
-
User List Permissions - - + + +
User List Permissions +
+ - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - -
Id - {{ element.id }} Id + {{element.id}} - Perform - - - {{ stringValue(element.logic.perform) }} - - + Perform + + + {{stringValue(element.logic.perform) | titlecase}} + + - Delegate - - - {{ stringValue(element.logic.delegate) }} - - + Delegate + + + {{stringValue(element.logic.delegate) | titlecase}} + + - Cancel - - - {{ stringValue(element.logic.cancel) }} - - + Cancel + + + {{stringValue(element.logic.cancel) | titlecase}} + + - Assign - - - {{ stringValue(element.logic.assign) }} - - + Assign + + + {{stringValue(element.logic.assign) | titlecase}} + + - View - - - {{ stringValue(element.logic.view) }} - - + View + + + {{stringValue(element.logic.view) | titlecase}} + + - Create - - - {{ stringValue(element.caseLogic.create) }} - - + Create + + + {{stringValue(element.logic.create) | titlecase}} + + - Delete - - - {{ stringValue(element.caseLogic.delete) }} - - + Delete + + + {{stringValue(element.logic.delete) | titlecase}} + + View - - - {{ stringValue(element.caseLogic.view) }} - - View + + + {{stringValue(element.logic.view) | titlecase}} + +
+ + + - -
+ +
diff --git a/src/app/dialogs/dialog-manage-roles/dialog-manage-roles.component.ts b/src/app/dialogs/dialog-manage-roles/dialog-manage-roles.component.ts index 470c880..e3beab2 100644 --- a/src/app/dialogs/dialog-manage-roles/dialog-manage-roles.component.ts +++ b/src/app/dialogs/dialog-manage-roles/dialog-manage-roles.component.ts @@ -1,240 +1,261 @@ -import {Component, Inject, OnInit, ViewChild} from '@angular/core'; +import {Component, Inject, OnDestroy, OnInit, ViewChild} from '@angular/core'; +import {MatTableDataSource} from '@angular/material/table'; import {MAT_DIALOG_DATA} from '@angular/material/dialog'; +import {MatSort, MatSortable, Sort} from '@angular/material/sort'; import {MatPaginator} from '@angular/material/paginator'; -import {MatSort} from '@angular/material/sort'; -import {MatTableDataSource} from '@angular/material/table'; -import {DataVariable, ProcessRoleRef, ProcessUserRef, Role, RoleRef, UserRef} from '@netgrif/petriflow'; -import {ModelService} from '../../modeler/services/model.service'; +import {DataVariable, ProcessPermissionRef, Role, TransitionPermissionRef} from '@netgrif/petriflow'; +import {ModelService} from '../../modeler/services/model/model.service'; +import {ModelerConfig} from '../../modeler/modeler-config'; +import {HistoryService} from '../../modeler/services/history/history.service'; +import {MAT_CHECKBOX_DEFAULT_OPTIONS, MatCheckboxDefaultOptions} from '@angular/material/checkbox'; export enum RoleRefType { - TRANSITION = 'transition', - PROCESS = 'process' + TRANSITION = 'transition', + PROCESS = 'process' } export interface ManagePermissionData { - type: RoleRefType; - roles: Array; - userLists: Array; - rolesRefs?: Array; - processRolesRefs?: Array; - userRefs?: Array; - processUserRefs?: Array; + type: RoleRefType; + roles: Array; + userLists: Array; + rolesRefs?: Array; + processRolesRefs?: Array; + userRefs?: Array; + processUserRefs?: Array; } @Component({ - selector: 'nab-dialog.manage-roles', - templateUrl: './dialog-manage-roles.component.html', - styleUrls: ['./dialog-manage-roles.component.scss'], + selector: 'nab-dialog.manage-roles', + templateUrl: './dialog-manage-roles.component.html', + styleUrls: ['./dialog-manage-roles.component.scss'], + providers: [ + {provide: MAT_CHECKBOX_DEFAULT_OPTIONS, useValue: {clickAction: 'noop'} as MatCheckboxDefaultOptions} + ] }) -export class DialogManageRolesComponent implements OnInit { - pageSizes = [5, 10, 20]; - defaultPageSize = 10; - displayedColumns: Array; - usersDisplayedColumns: Array; - dataSource: MatTableDataSource; - usersDataSource: MatTableDataSource; - @ViewChild('matPaginator', {static: true}) paginator: MatPaginator; - @ViewChild('matUserPaginator', {static: true}) userPaginator: MatPaginator; - @ViewChild('firstTableSort', {static: true}) sort: MatSort; - @ViewChild('secondTableSort', {static: true}) userSort: MatSort; - - constructor(@Inject(MAT_DIALOG_DATA) public data: ManagePermissionData, private modelService: ModelService) { - let arrayRoleRefs: Array | Array; - let arrayUserRefs: Array | Array; - if (this.data.type === RoleRefType.TRANSITION) { - arrayRoleRefs = [...this.data.rolesRefs]; - this.addDefaultRoleRefs(arrayRoleRefs); - arrayUserRefs = [...this.data.userRefs]; - this.displayedColumns = ['id', 'perform', 'delegate', 'cancel', 'assign', 'view']; - this.usersDisplayedColumns = ['id', 'perform', 'delegate', 'cancel', 'assign', 'view']; - this.data.roles.forEach(item => { - if (this.data.rolesRefs.find(itm => itm.id === item.id) === undefined) { - (arrayRoleRefs as Array).push(new RoleRef(item.id)); - } - }); - this.data.userLists.forEach(item => { - if (this.data.userRefs.find(itm => itm.id === item.id) === undefined) { - (arrayUserRefs as Array).push(new UserRef(item.id)); - } - }); - this.dataSource = new MatTableDataSource(arrayRoleRefs); - this.usersDataSource = new MatTableDataSource(arrayUserRefs); - } else { - arrayRoleRefs = [...this.data.processRolesRefs]; - this.addDefaultProcessRoleRefs(arrayRoleRefs); - arrayUserRefs = [...this.data.processUserRefs]; - this.displayedColumns = ['id', 'create', 'delete', 'processView']; - this.usersDisplayedColumns = ['id', 'create', 'delete', 'processView']; - this.data.roles.forEach(item => { - if (this.data.processRolesRefs.find(itm => itm.id === item.id) === undefined) { - (arrayRoleRefs as Array).push(new ProcessRoleRef(item.id)); - } - }); - this.data.userLists.forEach(item => { - if (this.data.processUserRefs.find(itm => itm.id === item.id) === undefined) { - (arrayUserRefs as Array).push(new ProcessUserRef(item.id)); - } - }); - this.dataSource = new MatTableDataSource(arrayRoleRefs); - this.usersDataSource = new MatTableDataSource(arrayUserRefs); - } - this.dataSource.sortingDataAccessor = (item, property) => { - switch (property) { - case 'perform': - return (item as RoleRef).logic.perform.toString(); - case 'delegate': - return (item as RoleRef).logic.delegate.toString(); - case 'cancel': - return (item as RoleRef).logic.cancel.toString(); - case 'assign': - return (item as RoleRef).logic.assign.toString(); - case 'create': - return (item as ProcessRoleRef).caseLogic.create.toString(); - case 'delete': - return (item as ProcessRoleRef).caseLogic.delete.toString(); - case 'view': - return (item as RoleRef).logic.view.toString(); - case 'processView': - return (item as ProcessRoleRef).caseLogic.view.toString(); - default: - return item[property]; - } - }; - } - - ngOnInit() { - this.dataSource.paginator = this.paginator; - this.usersDataSource.paginator = this.userPaginator; - this.dataSource.sort = this.sort; - this.usersDataSource.sort = this.userSort; - } - - setValue($event, id: string, change: string) { - if (this.data.type === RoleRefType.TRANSITION) { - this.setRoleRef(this.data.rolesRefs.find(item => item.id === id), id, change); - } else { - this.setProcessRoleRef(this.data.processRolesRefs.find(item => item.id === id), id, change); - } - } - - setUserValue($event, id: string, change: string) { - if (this.data.type === RoleRefType.TRANSITION) { - this.setUserRef(this.data.userRefs.find(item => item.id === id), id, change); - } else { - this.setProcessUserRef(this.data.processUserRefs.find(item => item.id === id), id, change); - } - } - - stringValue(logic: boolean) { - if (logic === undefined) { - return ' '; - } else if (logic === true) { - return 'True'; - } else { - return 'False'; - } - } - - getChecked(logic: boolean) { - if (logic === undefined) { - return false; - } else if (logic === true) { - return true; - } - return undefined; - } - - getIndeterminate(logic: boolean) { - return !(logic === undefined || logic === true); - } - - protected resolveNewValue(roleRef, change) { - let newValue; - if (roleRef.logic[change] === undefined) { - newValue = true; - } else if (roleRef.logic[change] === true) { - newValue = false; - } - return newValue; - } - - protected resolveNewProcessValue(roleRef, change) { - let newValue; - if (roleRef.caseLogic[change] === undefined) { - newValue = true; - } else if (roleRef.caseLogic[change] === true) { - newValue = false; - } - return newValue; - } - - private setRoleRef(roleRef: RoleRef, id: string, change: string) { - if (roleRef === undefined) { - this.data.rolesRefs.push(new RoleRef(id)); - this.data.rolesRefs.find(item => item.id === id).logic[change] = true; - (this.dataSource.data.find(item => item.id === id) as RoleRef).logic[change] = true; - } else { - const newValue = this.resolveNewValue(roleRef, change); - this.data.rolesRefs.find(item => item.id === id).logic[change] = newValue; - (this.dataSource.data.find(item => item.id === id) as RoleRef).logic[change] = newValue; - } - } - - private setProcessRoleRef(processRoleRef: ProcessRoleRef, id: string, change: string) { - if (processRoleRef === undefined) { - const roleRef = new ProcessRoleRef(id); - this.data.processRolesRefs.push(roleRef); - this.modelService.model.addRoleRef(roleRef); - this.data.processRolesRefs.find(item => item.id === id).caseLogic[change] = true; - (this.dataSource.data.find(item => item.id === id) as ProcessRoleRef).caseLogic[change] = true; - } else { - const newValue = this.resolveNewProcessValue(processRoleRef, change); - this.data.processRolesRefs.find(item => item.id === id).caseLogic[change] = newValue; - (this.dataSource.data.find(item => item.id === id) as ProcessRoleRef).caseLogic[change] = newValue; - } - } - - private setUserRef(userRef: UserRef, id: string, change: string) { - if (userRef === undefined) { - this.data.userRefs.push(new UserRef(id)); - this.data.userRefs.find(item => item.id === id).logic[change] = true; - (this.usersDataSource.data.find(item => item.id === id) as UserRef).logic[change] = true; - } else { - const newValue = this.resolveNewValue(userRef, change); - this.data.userRefs.find(item => item.id === id).logic[change] = newValue; - (this.usersDataSource.data.find(item => item.id === id) as UserRef).logic[change] = newValue; - } - } - - private setProcessUserRef(processUserRef: ProcessUserRef, id: string, change: string) { - if (processUserRef === undefined) { - const ref = new ProcessUserRef(id); - this.data.processUserRefs.push(ref); - this.modelService.model.addUserRef(ref); - this.data.processUserRefs.find(item => item.id === id).caseLogic[change] = true; - (this.usersDataSource.data.find(item => item.id === id) as ProcessUserRef).caseLogic[change] = true; - } else { - const newValue = this.resolveNewProcessValue(processUserRef, change); - this.data.processUserRefs.find(item => item.id === id).caseLogic[change] = newValue; - (this.usersDataSource.data.find(item => item.id === id) as ProcessUserRef).caseLogic[change] = newValue; - } - } - - private addDefaultRoleRefs(arrayRoleRefs: Array) { - if (!arrayRoleRefs.find(roleRef => roleRef.id === Role.DEFAULT)) { - arrayRoleRefs.push(new RoleRef(Role.DEFAULT)); - } - if (!arrayRoleRefs.find(roleRef => roleRef.id === Role.ANONYMOUS)) { - arrayRoleRefs.push(new RoleRef(Role.ANONYMOUS)); - } - } - - private addDefaultProcessRoleRefs(arrayRoleRefs: Array) { - if (!arrayRoleRefs.find(roleRef => roleRef.id === Role.DEFAULT)) { - arrayRoleRefs.push(new ProcessRoleRef(Role.DEFAULT)); - } - if (!arrayRoleRefs.find(roleRef => roleRef.id === Role.ANONYMOUS)) { - arrayRoleRefs.push(new ProcessRoleRef(Role.ANONYMOUS)); - } - } +export class DialogManageRolesComponent implements OnInit, OnDestroy { + pageSizes = [5, 10, 20]; + defaultPageSize = 10; + displayedColumns: Array; + usersDisplayedColumns: Array; + dataSource: MatTableDataSource; + usersDataSource: MatTableDataSource; + @ViewChild('matPaginator', {static: true}) paginator: MatPaginator; + @ViewChild('matUserPaginator', {static: true}) userPaginator: MatPaginator; + @ViewChild('firstTableSort', {static: true}) sort: MatSort; + @ViewChild('secondTableSort', {static: true}) userSort: MatSort; + private historyChange: boolean; + + constructor( + @Inject(MAT_DIALOG_DATA) public data: ManagePermissionData, + private modelService: ModelService, + private historyService: HistoryService + ) { + if (this.data.type === RoleRefType.TRANSITION) { + const arrayRoleRefs = [...this.data.rolesRefs]; + this.addDefaultRoleRefs(arrayRoleRefs); + const arrayUserRefs = [...this.data.userRefs]; + this.displayedColumns = ['id', 'perform', 'delegate', 'cancel', 'assign', 'view']; + this.usersDisplayedColumns = ['id', 'perform', 'delegate', 'cancel', 'assign', 'view']; + this.data.roles.forEach(item => { + if (this.data.rolesRefs.find(itm => itm.id === item.id) === undefined) { + (arrayRoleRefs as Array).push(new TransitionPermissionRef(item.id)); + } + }); + this.data.userLists.forEach(item => { + if (this.data.userRefs.find(itm => itm.id === item.id) === undefined) { + (arrayUserRefs as Array).push(new TransitionPermissionRef(item.id)); + } + }); + this.dataSource = new MatTableDataSource(arrayRoleRefs); + this.usersDataSource = new MatTableDataSource(arrayUserRefs); + } else { + const arrayRoleRefs = [...this.data.processRolesRefs]; + this.addDefaultProcessRoleRefs(arrayRoleRefs); + const arrayUserRefs = [...this.data.processUserRefs]; + this.displayedColumns = ['id', 'create', 'delete', 'view']; + this.usersDisplayedColumns = ['id', 'create', 'delete', 'view']; + this.data.roles.forEach(item => { + if (this.data.processRolesRefs.find(itm => itm.id === item.id) === undefined) { + (arrayRoleRefs as Array).push(new ProcessPermissionRef(item.id)); + } + }); + this.data.userLists.forEach(item => { + if (this.data.processUserRefs.find(itm => itm.id === item.id) === undefined) { + (arrayUserRefs as Array).push(new ProcessPermissionRef(item.id)); + } + }); + this.dataSource = new MatTableDataSource(arrayRoleRefs); + this.usersDataSource = new MatTableDataSource(arrayUserRefs); + } + this.dataSource.sortData = (data: (TransitionPermissionRef | ProcessPermissionRef)[], sort: MatSort): (TransitionPermissionRef | ProcessPermissionRef)[] => { + return this.sortRefs(sort, data) as (TransitionPermissionRef | ProcessPermissionRef)[]; + }; + this.usersDataSource.sortData = (data: (TransitionPermissionRef | ProcessPermissionRef)[], sort: MatSort): (TransitionPermissionRef | ProcessPermissionRef)[] => { + return this.sortRefs(sort, data) as (TransitionPermissionRef | ProcessPermissionRef)[]; + } + } + + private sortRefs(sort: MatSort, data: ((TransitionPermissionRef | ProcessPermissionRef)[])) { + if (sort.active === undefined) { + return data; + } + const order = sort.direction === 'desc' ? -1 : (sort.direction === 'asc' ? 1 : 0); + return data.sort((a: TransitionPermissionRef | ProcessPermissionRef, b: TransitionPermissionRef | ProcessPermissionRef) => { + const refA = this.refStringValue(a, sort.active); + const refB = this.refStringValue(b, sort.active); + if (refA === refB || order === 0) { + return a.id.localeCompare(b.id); + } + return refA.localeCompare(refB) * order; + }); + } + + refStringValue(item: TransitionPermissionRef | ProcessPermissionRef, property: string): string { + const value: boolean | undefined = item.logic[property]; + return value === undefined ? '' : `${value.toString()}`; + } + + ngOnInit() { + this.dataSource.paginator = this.paginator; + this.usersDataSource.paginator = this.userPaginator; + this.dataSource.sort = this.sort; + this.usersDataSource.sort = this.userSort; + this.sort.sort(({ + id: localStorage.getItem(ModelerConfig.LOCALSTORAGE.PERMISSION_DIALOG.ROLE_SORT), + start: localStorage.getItem(ModelerConfig.LOCALSTORAGE.PERMISSION_DIALOG.ROLE_DIRECTION) + }) as MatSortable); + this.userSort.sort(({ + id: localStorage.getItem(ModelerConfig.LOCALSTORAGE.PERMISSION_DIALOG.USER_REF_SORT), + start: localStorage.getItem(ModelerConfig.LOCALSTORAGE.PERMISSION_DIALOG.USER_REF_DIRECTION) + }) as MatSortable); + } + + setValue(id: string, change: string) { + if (this.data.type === RoleRefType.TRANSITION) { + this.setRoleRef(this.data.rolesRefs.find(item => item.id === id), id, change); + } else { + this.setProcessRoleRef(this.data.processRolesRefs.find(item => item.id === id), id, change); + } + this.historyChange = true; + } + + setUserValue(id: string, change: string) { + if (this.data.type === RoleRefType.TRANSITION) { + this.setUserRef(this.data.userRefs.find(item => item.id === id), id, change); + } else { + this.setProcessUserRef(this.data.processUserRefs.find(item => item.id === id), id, change); + } + this.historyChange = true; + } + + private setRoleRef(roleRef: TransitionPermissionRef, id: string, change: string) { + if (roleRef === undefined) { + this.data.rolesRefs.push(new TransitionPermissionRef(id)); + this.data.rolesRefs.find(item => item.id === id).logic[change] = true; + (this.dataSource.data.find(item => item.id === id) as TransitionPermissionRef).logic[change] = true; + } else { + const newValue = this.resolveNewValue(roleRef, change); + this.data.rolesRefs.find(item => item.id === id).logic[change] = newValue; + (this.dataSource.data.find(item => item.id === id) as TransitionPermissionRef).logic[change] = newValue; + } + } + + private setProcessRoleRef(processRoleRef: ProcessPermissionRef, id: string, change: string) { + if (processRoleRef === undefined) { + const roleRef = new ProcessPermissionRef(id); + this.data.processRolesRefs.push(roleRef); + this.modelService.model.addRoleRef(roleRef); + this.data.processRolesRefs.find(item => item.id === id).logic[change] = true; + (this.dataSource.data.find(item => item.id === id) as ProcessPermissionRef).logic[change] = true; + } else { + const newValue = this.resolveNewValue(processRoleRef, change); + this.data.processRolesRefs.find(item => item.id === id).logic[change] = newValue; + (this.dataSource.data.find(item => item.id === id) as ProcessPermissionRef).logic[change] = newValue; + } + } + + private setUserRef(userRef: TransitionPermissionRef, id: string, change: string) { + if (userRef === undefined) { + this.data.userRefs.push(new TransitionPermissionRef(id)); + this.data.userRefs.find(item => item.id === id).logic[change] = true; + (this.usersDataSource.data.find(item => item.id === id) as TransitionPermissionRef).logic[change] = true; + } else { + const newValue = this.resolveNewValue(userRef, change); + this.data.userRefs.find(item => item.id === id).logic[change] = newValue; + (this.usersDataSource.data.find(item => item.id === id) as TransitionPermissionRef).logic[change] = newValue; + } + } + + private setProcessUserRef(processUserRef: ProcessPermissionRef, id: string, change: string) { + if (processUserRef === undefined) { + const ref = new ProcessPermissionRef(id); + this.data.processUserRefs.push(ref); + this.modelService.model.addUserRef(ref); + this.data.processUserRefs.find(item => item.id === id).logic[change] = true; + (this.usersDataSource.data.find(item => item.id === id) as ProcessPermissionRef).logic[change] = true; + } else { + const newValue = this.resolveNewValue(processUserRef, change); + this.data.processUserRefs.find(item => item.id === id).logic[change] = newValue; + (this.usersDataSource.data.find(item => item.id === id) as ProcessPermissionRef).logic[change] = newValue; + } + } + + protected resolveNewValue(roleRef: ProcessPermissionRef | TransitionPermissionRef, change: string) { + let newValue; + if (roleRef.logic[change] === undefined) { + newValue = true; + } else if (roleRef.logic[change] === true) { + newValue = false; + } + return newValue; + } + + stringValue(logic: boolean): string { + if (logic === undefined) { + return ' '; + } + return `${logic}`; + } + + getChecked(logic: boolean): boolean { + return logic === true; + } + + getIndeterminate(logic: boolean): boolean { + return logic === false; + } + + private addDefaultRoleRefs(arrayRoleRefs: Array) { + if (!arrayRoleRefs.find(roleRef => roleRef.id === Role.DEFAULT)) { + arrayRoleRefs.push(new TransitionPermissionRef(Role.DEFAULT)); + } + if (!arrayRoleRefs.find(roleRef => roleRef.id === Role.ANONYMOUS)) { + arrayRoleRefs.push(new TransitionPermissionRef(Role.ANONYMOUS)); + } + } + + private addDefaultProcessRoleRefs(arrayRoleRefs: Array) { + if (!arrayRoleRefs.find(roleRef => roleRef.id === Role.DEFAULT)) { + arrayRoleRefs.push(new ProcessPermissionRef(Role.DEFAULT)); + } + if (!arrayRoleRefs.find(roleRef => roleRef.id === Role.ANONYMOUS)) { + arrayRoleRefs.push(new ProcessPermissionRef(Role.ANONYMOUS)); + } + } + + sortRoleRefs(sort: Sort): void { + localStorage.setItem(ModelerConfig.LOCALSTORAGE.PERMISSION_DIALOG.ROLE_SORT, sort.active); + localStorage.setItem(ModelerConfig.LOCALSTORAGE.PERMISSION_DIALOG.ROLE_DIRECTION, sort.direction); + } + + sortUserRefs(sort: Sort): void { + localStorage.setItem(ModelerConfig.LOCALSTORAGE.PERMISSION_DIALOG.USER_REF_SORT, sort.active); + localStorage.setItem(ModelerConfig.LOCALSTORAGE.PERMISSION_DIALOG.USER_REF_DIRECTION, sort.direction); + } + + ngOnDestroy(): void { + if (this.historyChange) { + this.historyService.save("Role assignments has been changed."); + } + } } diff --git a/src/app/dialogs/dialog-model-edit/dialog-model-edit.component.html b/src/app/dialogs/dialog-model-edit/dialog-model-edit.component.html new file mode 100644 index 0000000..4611105 --- /dev/null +++ b/src/app/dialogs/dialog-model-edit/dialog-model-edit.component.html @@ -0,0 +1,87 @@ +

Edit model

+ + + Id + + Id is required + + + Version + + + + Version must be in format Major.Minor.Patch + + + Title + + Id is required + + + Initials + + Id is required + + +
+ + Default role + + + Anonymous role + +
+ + Default case name + + +
+ Tags +
+
+
+
+
+
+ + Key + + + + Value + + + +
+
+
+ Empty +
+
+
+ +
+
+
+
+ + + + + diff --git a/src/app/dialogs/dialog-model-edit/dialog-model-edit.component.scss b/src/app/dialogs/dialog-model-edit/dialog-model-edit.component.scss new file mode 100644 index 0000000..de652ee --- /dev/null +++ b/src/app/dialogs/dialog-model-edit/dialog-model-edit.component.scss @@ -0,0 +1,22 @@ +mat-dialog-content { + display: flex; + flex-direction: column; +} + +mat-dialog-actions { + display: flex; + flex-direction: row; + justify-content: flex-end; +} + +.padding-top { + padding-top: 16px; +} + +.margin-right8px { + margin-right: 6px; +} + +.margin-html { + margin-top: 6px; +} diff --git a/src/app/dialogs/dialog-model-edit/dialog-model-edit.component.ts b/src/app/dialogs/dialog-model-edit/dialog-model-edit.component.ts new file mode 100644 index 0000000..7c13d1f --- /dev/null +++ b/src/app/dialogs/dialog-model-edit/dialog-model-edit.component.ts @@ -0,0 +1,110 @@ +import {Component, Inject} from '@angular/core'; +import {MAT_DIALOG_DATA, MatDialog} from '@angular/material/dialog'; +import {ModelService} from '../../modeler/services/model/model.service'; +import {Router} from '@angular/router'; +import {DialogManageRolesComponent, RoleRefType} from '../dialog-manage-roles/dialog-manage-roles.component'; +import {DataType} from '@netgrif/petriflow'; +import {FormControl, ValidatorFn, Validators} from '@angular/forms'; +import {ModelChange} from '../../modeler/history-mode/model/model/model-change'; +import {ActionsModeService} from '../../modeler/actions-mode/actions-mode.service'; +import {ProcessActionsTool} from '../../modeler/actions-mode/tools/process-actions-tool'; + +@Component({ + selector: 'nab-dialog-model-edit', + templateUrl: './dialog-model-edit.component.html', + styleUrls: ['./dialog-model-edit.component.scss'] +}) +export class DialogModelEditComponent { + + public model: ModelChange; + public idCtrl: FormControl; + public versionCtrl: FormControl; + public titleCtrl: FormControl; + public initialsCtrl: FormControl; + protected counterTags = 0; + + constructor( + @Inject(MAT_DIALOG_DATA) public data: ModelChange, + public modelService: ModelService, + private router: Router, + private dialog: MatDialog, + private _actionMode: ActionsModeService, + private _processTool: ProcessActionsTool + ) { + this.model = data; + this.idCtrl = new FormControl('', [Validators.required]); + this.versionCtrl = new FormControl('', [ + // Validators.required, + this.validVersion() + ]); + this.titleCtrl = new FormControl('', [Validators.required]); + this.initialsCtrl = new FormControl('', [Validators.required]); + } + + openPermissions() { + this.dialog.open(DialogManageRolesComponent, { + width: '60%', + panelClass: "dialog-width-60", + data: { + type: RoleRefType.PROCESS, + roles: this.modelService.model.getRoles(), + processRolesRefs: this.modelService.model.getRoleRefs(), + processUserRefs: this.modelService.model.getUserRefs(), + userLists: this.modelService.model.getDataSet().filter(item => item.type === DataType.USER_LIST) + } + }); + } + + openActions() { + this._actionMode.activate(this._processTool); + this.router.navigate(['modeler/actions']); + } + + private validVersion(): ValidatorFn { + return (fc: FormControl): { [key: string]: any } | null => { + const version = fc.value as string; + if (!version || version.length === 0) { + return null; + } + if (version.match(/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/)) { + return null; + } + return ({format: true}) + }; + } + + getTags() { + return Array.from(this.model.model.tags, ([key, value]) => ({ key, value })); + } + + addTag() { + this.model.model.tags.set(this.createKeyId() , 'value'); + } + + deleteTag(key: string) { + this.model.model.tags.delete(key); + } + + setKey($event, key: string) { + const value = this.model.model.tags.get(key); + this.model.model.tags.delete(key); + this.model.model.tags.set($event.target.value, value); + } + + setValue($event, key: string) { + this.model.model.tags.set(key, $event.target.value); + } + + trackByFn(index: any, item: any) { + return index + item.key; + } + + createKeyId(): string { + this.counterTags++; + if (this.model.model.tags.has('key' + this.counterTags)) { + return this.createKeyId(); + } else { + return 'key' + String(this.counterTags); + } + } +} diff --git a/src/app/dialogs/dialog-place-edit/dialog-place-edit.component.html b/src/app/dialogs/dialog-place-edit/dialog-place-edit.component.html new file mode 100644 index 0000000..4364aea --- /dev/null +++ b/src/app/dialogs/dialog-place-edit/dialog-place-edit.component.html @@ -0,0 +1,28 @@ +

Edit place

+ + + Id + + Id is required + Place with given id already exists + + + Label + + + + Tokens + + Id is required + + Number of tokens must be a non-negative integer + + + + + + diff --git a/src/app/dialogs/dialog-place-edit/dialog-place-edit.component.scss b/src/app/dialogs/dialog-place-edit/dialog-place-edit.component.scss new file mode 100644 index 0000000..a8e2222 --- /dev/null +++ b/src/app/dialogs/dialog-place-edit/dialog-place-edit.component.scss @@ -0,0 +1,9 @@ +mat-dialog-content { + display: flex; + flex-direction: column; +} + +mat-dialog-actions { + justify-content: flex-end; +} + diff --git a/src/app/dialogs/dialog-place-edit/dialog-place-edit.component.ts b/src/app/dialogs/dialog-place-edit/dialog-place-edit.component.ts new file mode 100644 index 0000000..a55caf6 --- /dev/null +++ b/src/app/dialogs/dialog-place-edit/dialog-place-edit.component.ts @@ -0,0 +1,57 @@ +import {Component, Inject} from '@angular/core'; +import {ModelService} from '../../modeler/services/model/model.service'; +import {MAT_DIALOG_DATA} from '@angular/material/dialog'; +import {PlaceChange} from '../../modeler/history-mode/model/place/place-change'; +import {FormControl, ValidatorFn, Validators} from '@angular/forms'; + +export interface PlaceEditData { + placeId: string; +} + +@Component({ + selector: 'nab-dialog-place-edit', + templateUrl: './dialog-place-edit.component.html', + styleUrls: ['./dialog-place-edit.component.scss'] +}) +export class DialogPlaceEditComponent { + + public place: PlaceChange; + public idCtrl: FormControl; + public markingCtrl: FormControl; + + constructor( + @Inject(MAT_DIALOG_DATA) public data: PlaceEditData, + public modelService: ModelService + ) { + const modelPlace = this.modelService.model.getPlace(data.placeId); + this.place = new PlaceChange(modelPlace.clone(), modelPlace.clone(), undefined); + this.idCtrl = new FormControl('', [ + Validators.required, + this.validUnique() + ]); + this.markingCtrl = new FormControl('', [ + Validators.required, + this.validMarking() + ]); + } + + private validUnique(): ValidatorFn { + return (fc: FormControl): { [key: string]: any } | null => { + if (this.modelService.model.getPlace(fc.value) !== undefined && fc.value !== this.place.originalPlace.id) { + return ({validUnique: true}); + } else { + return null; + } + }; + } + + private validMarking(): ValidatorFn { + return (fc: FormControl): { [key: string]: any } | null => { + const marking = Math.floor(fc.value as number); + if (marking !== Infinity && marking === fc.value as number && marking >= 0) { + return null; + } + return ({validMarking: true}) + }; + } +} diff --git a/src/app/dialogs/dialog-place-ref-delete/dialog-place-ref-delete.component.html b/src/app/dialogs/dialog-place-ref-delete/dialog-place-ref-delete.component.html index a37f636..052c8cc 100644 --- a/src/app/dialogs/dialog-place-ref-delete/dialog-place-ref-delete.component.html +++ b/src/app/dialogs/dialog-place-ref-delete/dialog-place-ref-delete.component.html @@ -1,9 +1,9 @@ -

Delete referenced place?

+

Delete referenced place{{data.length > 1 ? 's' : ''}}?

-

Place {{ placeLabel() }} is referenced by arc{{ data.arcs.length > 1 ? 's' : '' }}: {{ arcs() }}. Are you sure you - want to delete it?

+ Place {{placeLabel(refData)}} + is referenced by arc{{refData.arcs.length > 1 ? 's' : ''}}: {{arcs(refData)}}.
- - + + diff --git a/src/app/dialogs/dialog-place-ref-delete/dialog-place-ref-delete.component.scss b/src/app/dialogs/dialog-place-ref-delete/dialog-place-ref-delete.component.scss index e69de29..faaf097 100644 --- a/src/app/dialogs/dialog-place-ref-delete/dialog-place-ref-delete.component.scss +++ b/src/app/dialogs/dialog-place-ref-delete/dialog-place-ref-delete.component.scss @@ -0,0 +1,4 @@ +mat-dialog-content { + display: flex; + flex-direction: column; +} diff --git a/src/app/dialogs/dialog-place-ref-delete/dialog-place-ref-delete.component.ts b/src/app/dialogs/dialog-place-ref-delete/dialog-place-ref-delete.component.ts index 8618c49..781c8c6 100644 --- a/src/app/dialogs/dialog-place-ref-delete/dialog-place-ref-delete.component.ts +++ b/src/app/dialogs/dialog-place-ref-delete/dialog-place-ref-delete.component.ts @@ -1,28 +1,28 @@ import {Component, Inject} from '@angular/core'; import {MAT_DIALOG_DATA} from '@angular/material/dialog'; import {Arc} from '@netgrif/petriflow'; -import {Place} from '../../modeler/classes/place/place'; +import {CanvasPlace} from '../../modeler/edit-mode/domain/canvas-place'; export interface PlaceRefDeleteData { - place: Place; - arcs: Array; + place: CanvasPlace; + arcs: Array>; } @Component({ - selector: 'nab-dialog-place-ref-delete', - templateUrl: './dialog-place-ref-delete.component.html', - styleUrls: ['./dialog-place-ref-delete.component.scss'], + selector: 'nab-dialog-place-ref-delete', + templateUrl: './dialog-place-ref-delete.component.html', + styleUrls: ['./dialog-place-ref-delete.component.scss'] }) export class DialogPlaceRefDeleteComponent { - constructor(@Inject(MAT_DIALOG_DATA) public data: PlaceRefDeleteData) { - } + constructor(@Inject(MAT_DIALOG_DATA) public data: Array) { + } - public placeLabel(): string { - return this.data.place.getLabelOrId(); - } + public placeLabel(data: PlaceRefDeleteData): string { + return data.place.modelPlace.label.value; + } - public arcs(): string { - return this.data.arcs.map(arc => arc.id).join(', '); - } + public arcs(data: PlaceRefDeleteData): string { + return data.arcs.map(arc => arc.id).join(', '); + } } diff --git a/src/app/dialogs/dialog-refactor/dialog-refactor.component.html b/src/app/dialogs/dialog-refactor/dialog-refactor.component.html index 0101b97..8747e75 100644 --- a/src/app/dialogs/dialog-refactor/dialog-refactor.component.html +++ b/src/app/dialogs/dialog-refactor/dialog-refactor.component.html @@ -1,26 +1,22 @@

Refactor Id

- - - Original Id - - - - New Id - - New Id is required! - Id can contain only alphanumeric characters, - dash or underscore! - - Id must be unique! Selected Id already - exists! - - -
- WARNING! In actions, field Id will be changed only in the declaration part, + + + Original Id + + + + New Id + + New Id is required! + Id can contain only alphanumeric characters, dash or underscore! + Id must be unique! Selected Id already exists! + +
+ WARNING! In actions, field Id will be changed only in the declaration part, Id used as string in the actions statement will not be changed.
- - + + diff --git a/src/app/dialogs/dialog-refactor/dialog-refactor.component.spec.ts b/src/app/dialogs/dialog-refactor/dialog-refactor.component.spec.ts index a13e1f2..6d5b398 100644 --- a/src/app/dialogs/dialog-refactor/dialog-refactor.component.spec.ts +++ b/src/app/dialogs/dialog-refactor/dialog-refactor.component.spec.ts @@ -1,47 +1,46 @@ -import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; -import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; -import {NoopAnimationsModule} from '@angular/platform-browser/animations'; -import {Model} from '@netgrif/petriflow'; -import {Subject} from 'rxjs'; -import {MaterialImportModule} from '../../material-import/material-import.module'; -import {ModelService} from '../../modeler/services/model.service'; +import {waitForAsync, ComponentFixture, TestBed} from '@angular/core/testing'; import {DialogRefactorComponent} from './dialog-refactor.component'; +import {MaterialImportModule} from '../../material-import/material-import.module'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; +import {ModelService} from '../../modeler/services/model/model.service'; +import {Subject} from 'rxjs'; +import {NoopAnimationsModule} from '@angular/platform-browser/animations'; +import {PetriNet} from '@netgrif/petriflow'; describe('DialogRefactorComponent', () => { - let component: DialogRefactorComponent; - let fixture: ComponentFixture; + let component: DialogRefactorComponent; + let fixture: ComponentFixture; - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - declarations: [DialogRefactorComponent], - imports: [MaterialImportModule, NoopAnimationsModule], - providers: [ - { - provide: MatDialogRef, useValue: { - beforeClosed() { - return new Subject(); - }, - }, - }, - {provide: MAT_DIALOG_DATA, useValue: []}, - {provide: ModelService, useClass: MockModelService}, - ], - }) - .compileComponents(); - })); + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [DialogRefactorComponent], + imports: [MaterialImportModule, NoopAnimationsModule], + providers: [ + { provide: MatDialogRef, useValue: { + beforeClosed() { + return new Subject(); + } + } + }, + { provide: MAT_DIALOG_DATA, useValue: [] }, + { provide: ModelService, useClass: MockModelService} + ] + }) + .compileComponents(); + })); - beforeEach(() => { - fixture = TestBed.createComponent(DialogRefactorComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(DialogRefactorComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); class MockModelService { - model = new Model(); + model = new PetriNet(); } diff --git a/src/app/dialogs/dialog-refactor/dialog-refactor.component.ts b/src/app/dialogs/dialog-refactor/dialog-refactor.component.ts index 558bf1f..ac239d3 100644 --- a/src/app/dialogs/dialog-refactor/dialog-refactor.component.ts +++ b/src/app/dialogs/dialog-refactor/dialog-refactor.component.ts @@ -1,136 +1,129 @@ -import {Component, Inject, OnInit} from '@angular/core'; -import {FormControl, ValidatorFn, Validators} from '@angular/forms'; +import {Component, Inject} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; -import {Action, Event} from '@netgrif/petriflow'; +import {FormControl, ValidatorFn, Validators} from '@angular/forms'; +import {ModelService} from '../../modeler/services/model/model.service'; import escapeStringRegexp from 'escape-string-regexp'; -import {ModelService} from '../../modeler/services/model.service'; +import {Action, Event} from '@netgrif/petriflow'; export interface DialogRefactorData { - originalId: string; + originalId: string; } @Component({ - selector: 'nab-dialog-refactor', - templateUrl: './dialog-refactor.component.html', - styleUrls: ['./dialog-refactor.component.scss'], + selector: 'nab-dialog-refactor', + templateUrl: './dialog-refactor.component.html', + styleUrls: ['./dialog-refactor.component.scss'] }) -export class DialogRefactorComponent implements OnInit { +export class DialogRefactorComponent { - formControl: FormControl; - result: string; + formControl: FormControl; + result: string; - constructor(public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: DialogRefactorData, - protected modelService: ModelService) { - this.formControl = new FormControl('', [ - Validators.required, - Validators.pattern('^[a-zA-Z0-9-_]+$'), - this.validUnique(), - ]); - } - - ngOnInit(): void { - this.dialogRef.beforeClosed().subscribe(() => this.dialogRef.close(this.result)); - } - - refactor() { - if (this.formControl.valid) { - this.result = this.formControl.value; - this.fieldIdRefactor(); + constructor( + public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: DialogRefactorData, + protected modelService: ModelService + ) { + this.formControl = new FormControl('', [ + Validators.required, + Validators.pattern('^[a-zA-Z0-9-_]+$'), + this.validUnique() + ]); } - } - close(): void { - this.dialogRef.close(); - } - - protected fieldIdRefactor() { - const refactoredModel = this.modelService.model; - const dataField = refactoredModel.getData(this.data.originalId); - this.changedIfExist(dataField); - refactoredModel.removeData(this.data.originalId); - refactoredModel.addData(dataField); - if (!refactoredModel.getPlace(this.data.originalId)) { - const arc = refactoredModel.getArc(this.data.originalId); - if (arc !== undefined) { - arc.reference = this.formControl.value; - } + refactor() { + if (this.formControl.valid) { + this.result = this.formControl.value; + this.fieldIdRefactor(); + } } - refactoredModel.getArcs().forEach(arc => { - if (arc.reference === this.data.originalId) { - arc.reference = this.formControl.value; - } - }); - refactoredModel.getDataSet().forEach(data => { - data.getEvents().forEach(event => { - this.refactorEventActions(event); - }); - }); - refactoredModel.getCaseEvents().forEach(event => { - this.refactorEventActions(event); - }); - refactoredModel.getProcessEvents().forEach(event => { - this.refactorEventActions(event); - }); - const processUserRef = refactoredModel.getUserRef(this.data.originalId); - if (processUserRef) { - refactoredModel.removeUserRef(this.data.originalId); - processUserRef.id = this.formControl.value; - refactoredModel.addUserRef(processUserRef); + + close(): void { + this.dialogRef.close(); } - refactoredModel.getTransitions().forEach(trans => { - trans.dataGroups.forEach(group => { - const oldDataRef = group.getDataRef(this.data.originalId); - if (oldDataRef) { - group.removeDataRef(this.data.originalId); - oldDataRef.id = this.formControl.value; - group.addDataRef(oldDataRef); + protected fieldIdRefactor() { + const refactoredModel = this.modelService.model; + const dataField = refactoredModel.getData(this.data.originalId); + this.changedIfExist(dataField); + refactoredModel.removeData(this.data.originalId); + refactoredModel.addData(dataField); + if (!refactoredModel.getPlace(this.data.originalId)) { + const arc = refactoredModel.getArc(this.data.originalId); + if (arc !== undefined) { + arc.reference = this.formControl.value; + } } - group.getDataRefs().forEach(d => d.getEvents().forEach(event => { - this.refactorEventActions(event); - })); - }); - trans.getEvents().forEach(event => { - this.refactorEventActions(event); - }); - trans.userRefs.forEach(ref => { - if (ref.id === this.data.originalId) { - ref.id = this.formControl.value; + refactoredModel.getArcs().forEach(arc => { + if (arc.reference === this.data.originalId) { + arc.reference = this.formControl.value; + } + }); + refactoredModel.getDataSet().forEach(data => { + data.getEvents().forEach(event => { + this.refactorEventActions(event); + }); + }); + refactoredModel.getCaseEvents().forEach(event => { + this.refactorEventActions(event); + }); + refactoredModel.getProcessEvents().forEach(event => { + this.refactorEventActions(event); + }); + const processUserRef = refactoredModel.getUserRef(this.data.originalId); + if (processUserRef) { + refactoredModel.removeUserRef(this.data.originalId); + processUserRef.id = this.formControl.value; + refactoredModel.addUserRef(processUserRef); } - }); - // TODO: check - this.changedIfExist(this.modelService.graphicModel.transitions - .find(t => t.transition.id === trans.id)?.data - .find(data => data.dataVariable.id === this.data.originalId)?.dataVariable); - }); - this.changedIfExist(refactoredModel.getUserRef(this.data.originalId)); - // TODO: check - // this._fieldListService.existingFieldEvents.next(new GridsterExistingFieldEvent(EventType.REFACTORED, this.data.originalId, this.formControl.value)); - this.dialogRef.close(); - } - protected changedIfExist(data) { - if (data) { - data.id = this.formControl.value; + refactoredModel.getTransitions().forEach(trans => { + trans.dataGroups.forEach(group => { + const oldDataRef = group.getDataRef(this.data.originalId); + if (oldDataRef) { + group.removeDataRef(this.data.originalId); + oldDataRef.id = this.formControl.value; + group.addDataRef(oldDataRef); + } + group.getDataRefs().forEach(d => d.getEvents().forEach(event => { + this.refactorEventActions(event); + })); + }); + trans.eventSource.getEvents().forEach(event => { + this.refactorEventActions(event); + }); + trans.userRefs.forEach(ref => { + if (ref.id === this.data.originalId) { + ref.id = this.formControl.value; + } + }); + }); + this.changedIfExist(refactoredModel.getUserRef(this.data.originalId)); + this.dialogRef.close(); } - } - protected actionDefRefactor(action: Action, type: string) { - action.definition = action.definition.replace(new RegExp(`(${type}\.)(${escapeStringRegexp(this.data.originalId)})([,;])`, 'g'), `$1${this.formControl.value}$3`); - } + private refactorEventActions(event: Event) { + event.preActions.forEach(action => this.actionDefRefactor(action, 'f')); + event.postActions.forEach(action => this.actionDefRefactor(action, 'f')); + } - private refactorEventActions(event: Event) { - event.preActions.forEach(action => this.actionDefRefactor(action, 'f')); - event.postActions.forEach(action => this.actionDefRefactor(action, 'f')); - } + protected changedIfExist(data) { + if (data) { + data.id = this.formControl.value; + } + } - private validUnique(): ValidatorFn { - return (fc: FormControl): { [key: string]: any } | null => { - if (this.modelService.model.getData(fc.value) !== undefined) { - return ({validUnique: true}); - } else { - return null; - } - }; - } + protected actionDefRefactor(action: Action, type: string) { + action.definition = action.definition.replace(new RegExp(`(${type}\.)(${escapeStringRegexp(this.data.originalId)})([,;])`, 'g'), `$1${this.formControl.value}$3`); + } + + private validUnique(): ValidatorFn { + return (fc: FormControl): { [key: string]: any } | null => { + if (this.modelService.model.getData(fc.value) !== undefined) { + return ({validUnique: true}); + } else { + return null; + } + }; + } } diff --git a/src/app/dialogs/dialog-transition-edit/changed-transition.ts b/src/app/dialogs/dialog-transition-edit/changed-transition.ts new file mode 100644 index 0000000..f977896 --- /dev/null +++ b/src/app/dialogs/dialog-transition-edit/changed-transition.ts @@ -0,0 +1,14 @@ +import {PetriNet, Transition} from '@netgrif/petriflow'; + +export class ChangedTransition { + + public readonly id: string; + public readonly transition: Transition; + public readonly model: PetriNet; + + constructor(model?: PetriNet, transition?: Transition, id = transition?.id) { + this.id = id; + this.transition = transition; + this.model = model; + } +} diff --git a/src/app/dialogs/dialog-transition-edit/dialog-transition-edit.component.html b/src/app/dialogs/dialog-transition-edit/dialog-transition-edit.component.html new file mode 100644 index 0000000..0f21b32 --- /dev/null +++ b/src/app/dialogs/dialog-transition-edit/dialog-transition-edit.component.html @@ -0,0 +1,92 @@ +

Edit task

+ +
+ + Id + + Id is required + Transition with given id already exists + + + Label + + + @defer (on viewport) { + + } @placeholder { +
+ ...loading +
+ } + + Assign policy + + + {{opt}} + + + + + Finish policy + + + {{opt}} + + + +
+ + +
+ Tags +
+
+
+
+
+
+ + Key + + + + Value + + + +
+
+
+ Empty +
+
+
+ +
+
+
+
+ + + + + + diff --git a/src/app/dialogs/dialog-transition-edit/dialog-transition-edit.component.scss b/src/app/dialogs/dialog-transition-edit/dialog-transition-edit.component.scss new file mode 100644 index 0000000..9852f86 --- /dev/null +++ b/src/app/dialogs/dialog-transition-edit/dialog-transition-edit.component.scss @@ -0,0 +1,32 @@ +mat-dialog-content { + display: flex; + flex-direction: column; +} + +mat-dialog-actions { + display: flex; + flex-direction: row; + justify-content: flex-end; +} + +.icon-select { + align-items: center; +} + +.icon-preview { + padding-left: 8px; + padding-right: 8px; + overflow: hidden; +} + +.loading-text { + height: 65px; +} + +.margin-right8px { + margin-right: 6px; +} + +.margin-html { + margin-top: 6px; +} diff --git a/src/app/dialogs/dialog-transition-edit/dialog-transition-edit.component.ts b/src/app/dialogs/dialog-transition-edit/dialog-transition-edit.component.ts new file mode 100644 index 0000000..a6b1011 --- /dev/null +++ b/src/app/dialogs/dialog-transition-edit/dialog-transition-edit.component.ts @@ -0,0 +1,123 @@ +import {Component, Inject, OnInit} from '@angular/core'; +import {AssignPolicy, DataType, FinishPolicy} from '@netgrif/petriflow'; +import {MAT_DIALOG_DATA, MatDialog} from '@angular/material/dialog'; +import {ModelService} from '../../modeler/services/model/model.service'; +import {ChangedTransition} from './changed-transition'; +import {Router} from '@angular/router'; +import {SelectedTransitionService} from '../../modeler/selected-transition.service'; +import {FormControl, ValidatorFn, Validators} from '@angular/forms'; +import {DialogManageRolesComponent, RoleRefType} from '../dialog-manage-roles/dialog-manage-roles.component'; +import {ActionsModeService} from '../../modeler/actions-mode/actions-mode.service'; +import {ActionsMasterDetailService} from '../../modeler/actions-mode/actions-master-detail.setvice'; + +export interface TransitionEditData { + transitionId: string; +} + +@Component({ + selector: 'nab-dialog-transition-edit', + templateUrl: './dialog-transition-edit.component.html', + styleUrls: ['./dialog-transition-edit.component.scss'] +}) +export class DialogTransitionEditComponent implements OnInit { + + public transition: ChangedTransition; + public assignPolicies: Array; + public finishPolicies: Array; + public form: FormControl; + protected counterTags = 0; + + constructor( + @Inject(MAT_DIALOG_DATA) public data: TransitionEditData, + public modelService: ModelService, + private router: Router, + private transitionService: SelectedTransitionService, + private dialog: MatDialog, + private _actionMode: ActionsModeService, + private _actionsMasterDetail: ActionsMasterDetailService + ) { + this.transition = new ChangedTransition(undefined, this.modelService.model.getTransition(data.transitionId).clone()); + this.form = new FormControl('', [ + Validators.required, + this.validUnique() + ]); + } + + ngOnInit(): void { + this.assignPolicies = Object.values(AssignPolicy); + this.finishPolicies = Object.values(FinishPolicy); + } + + openFormBuilder() { + // TODO: NAB-326 refactor SelectedTransitionService + this.transitionService.id = this.transition.id; + this.router.navigate(['/form']); + } + + openActions() { + this._actionMode.activate(this._actionMode.transitionActionsTool); + this._actionsMasterDetail.select(this.transition.transition); + this.transitionService.id = this.transition.id; + this.router.navigate(['modeler/actions']); + } + + private validUnique(): ValidatorFn { + return (fc: FormControl): { [key: string]: any } | null => { + if (this.modelService.model.getTransition(fc.value) !== undefined && fc.value !== this.transition.id) { + return ({validUnique: true}); + } else { + return null; + } + }; + } + + openPermissions() { + this.dialog.open(DialogManageRolesComponent, { + width: '60%', + panelClass: "dialog-width-60", + data: { + type: RoleRefType.TRANSITION, + roles: this.modelService.model.getRoles(), + rolesRefs: this.transition.transition.roleRefs, + userRefs: this.transition.transition.userRefs, + userLists: this.modelService.model.getDataSet().filter(item => item.type === DataType.USER_LIST) + } + }); + } + + + getTags() { + return Array.from(this.transition.transition.tags, ([key, value]) => ({ key, value })); + } + + addTag() { + this.transition.transition.tags.set(this.createKeyId() , 'value'); + } + + deleteTag(key: string) { + this.transition.transition.tags.delete(key); + } + + setKey($event, key: string) { + const value = this.transition.transition.tags.get(key); + this.transition.transition.tags.delete(key); + this.transition.transition.tags.set($event.target.value, value); + } + + setValue($event, key: string) { + this.transition.transition.tags.set(key, $event.target.value); + } + + trackByFn(index: any, item: any) { + return index + item.key; + } + + createKeyId(): string { + this.counterTags++; + if (this.transition.transition.tags.has('key' + this.counterTags)) { + return this.createKeyId(); + } else { + return 'key' + String(this.counterTags); + } + } +} diff --git a/src/app/dialogs/dialog-transition-settings/dialog-transition-settings.component.html b/src/app/dialogs/dialog-transition-settings/dialog-transition-settings.component.html deleted file mode 100644 index cf849da..0000000 --- a/src/app/dialogs/dialog-transition-settings/dialog-transition-settings.component.html +++ /dev/null @@ -1,26 +0,0 @@ -

{{ transition.label?.value }}

-
- - Icon - - - - - Assign Policy - - - {{ policy }} - - - - - - Finish Policy - - - {{ policy }} - - - - -
diff --git a/src/app/dialogs/dialog-transition-settings/dialog-transition-settings.component.scss b/src/app/dialogs/dialog-transition-settings/dialog-transition-settings.component.scss deleted file mode 100644 index a6b24b9..0000000 --- a/src/app/dialogs/dialog-transition-settings/dialog-transition-settings.component.scss +++ /dev/null @@ -1,4 +0,0 @@ -.mat-dialog-content { - display: flex; - flex-direction: column; -} diff --git a/src/app/dialogs/dialog-transition-settings/dialog-transition-settings.component.ts b/src/app/dialogs/dialog-transition-settings/dialog-transition-settings.component.ts deleted file mode 100644 index 5f07af9..0000000 --- a/src/app/dialogs/dialog-transition-settings/dialog-transition-settings.component.ts +++ /dev/null @@ -1,24 +0,0 @@ -import {Component, OnInit} from '@angular/core'; -import {AssignPolicy, FinishPolicy, Transition} from '@netgrif/petriflow'; -import {SelectedTransitionService} from '../../modeler/selected-transition.service'; -import {ModelService} from '../../modeler/services/model.service'; - -@Component({ - selector: 'nab-dialog-transition-settings', - templateUrl: './dialog-transition-settings.component.html', - styleUrls: ['./dialog-transition-settings.component.scss'], -}) -export class DialogTransitionSettingsComponent implements OnInit { - transition: Transition; - assignPolicyOptions: Array; - finishPolicyOptions: Array; - - constructor(private modelService: ModelService, private transitionService: SelectedTransitionService) { - } - - ngOnInit(): void { - this.transition = this.modelService.model.getTransition(this.transitionService.id); - this.assignPolicyOptions = [AssignPolicy.MANUAL, AssignPolicy.AUTO]; - this.finishPolicyOptions = [FinishPolicy.MANUAL, FinishPolicy.AUTO_NO_DATA]; - } -} diff --git a/src/app/dialogs/dialog.service.ts b/src/app/dialogs/dialog.service.ts new file mode 100644 index 0000000..cb6d06b --- /dev/null +++ b/src/app/dialogs/dialog.service.ts @@ -0,0 +1,43 @@ +import {Injectable} from '@angular/core'; +import {DialogModelEditComponent} from './dialog-model-edit/dialog-model-edit.component'; +import {MatDialog} from '@angular/material/dialog'; +import {PetriNet} from '@netgrif/petriflow'; +import {ModelService} from '../modeler/services/model/model.service'; +import {ArcEditData, DialogArcEditComponent} from './dialog-arc-edit/dialog-arc-edit.component'; +import {ChangedArc} from './dialog-arc-edit/changed-arc'; +import {CanvasArc} from '../modeler/edit-mode/domain/canvas-arc'; +import {ModelChange} from '../modeler/history-mode/model/model/model-change'; + +@Injectable({ + providedIn: 'root' +}) +export class DialogService { + + constructor( + private dialog: MatDialog, + private modelService: ModelService + ) { + } + + public openModelEditDialog(model: PetriNet = this.modelService.model): void { + this.dialog.open(DialogModelEditComponent, { + width: '50%', + panelClass: "dialog-width-50", + data: new ModelChange(model, model.clone()) + }).afterClosed().subscribe((changedModel: ModelChange) => { + this.modelService.updateModel(changedModel); + }); + } + + public openArcEditDialog(arc: CanvasArc): void { + this.dialog.open(DialogArcEditComponent, { + width: '50%', + panelClass: "dialog-width-50", + data: { + arcId: arc.modelArc.id + } as ArcEditData + }).afterClosed().subscribe((editedArc: ChangedArc) => { + this.modelService.updateArc(editedArc); + }); + } +} diff --git a/src/app/form-builder/edit-panel/edit-panel.component.html b/src/app/form-builder/edit-panel/edit-panel.component.html index fed2ccd..7dbff4a 100644 --- a/src/app/form-builder/edit-panel/edit-panel.component.html +++ b/src/app/form-builder/edit-panel/edit-panel.component.html @@ -1,369 +1,382 @@ -
-
- - - - - -
Assign event
- - - - - - - -
Finish event
- - - - - - +
+
+ + Number of columns + + -
Cancel event
- - - - - - + -
Delegate event
- - - - - - +
Assign event
+ + Title + + + + Message + + - -
- - - -
+
Finish event
+ + Title + + + + Message + + - -
-
-

- Id: {{ dataVariable.id }} - -

+
Cancel event
+ + Title + + + + Message + + -
- - Required - - - Behavior - - - {{ opt.value }} - - - +
Delegate event
+ + Title + + + + Message + +
-
- - - - - - - - - - - - - - - Initial value - - None - - {{ opt.value?.value }} - - - - - - {{ opt.value?.value }} - - - - - - Initial value - - - - - -
- - - - +

+ Id: {{ dataVariable.id }} + +

+ +
+ + Required + + + Immediate + + + Behavior + + + {{ opt.value }} + + +
- - - - - - - - - Initial value - - - - {{ taskRefTitle(option) }} - - - - -
- -
-
-
- drag_indicator - - - - - - - + +
+ + Title + + + + Placeholder + + + + Description + + + + + Initial value + + + + Initial value + + None + + {{ opt.value?.value }} + + + + + + {{ opt.value?.value }} + + + + + + Initial value + + + Initial value + + + + Initial value + + + + + + + Initial value + + + + + + + Initial value + + + + {{ taskRefTitle(option) }} + + + + +
+ +
+
+
+ drag_indicator + + + + + + + +
+
+
+ No options +
+
+
-
-
- No options -
-
- -
- + -
- -
-
- - - -
-
-
- - - - - - - -
-
-
- No properties -
-
- -
-
-
- - - - - - - +
+
-
- -
- No Icons +
+ + Component Name + + +
+
+
+ + + + + + + +
+
+
+ No properties +
+
+ +
+
+
+ + + + + + + +
+
+ +
+ No Icons +
+
+ +
- - -
-
- + -
- -
-
- - - -
-
-
- - - - - - - +
+
-
-
- No properties -
-
- -
-
-
- - - - - - - +
+ + Component Name + + +
+
+
+ + + + + + + +
+
+
+ No properties +
+
+ +
+
+
+ + + + + + + +
+
+ +
+ No Icons +
+
+
-
- -
- No Icons + +
+
- -
-
- + - - - Template - - - {{ opt }} - - - - - Appearance - - - {{ opt }} - - - -
- - - -
+ + + Template + + + {{ opt }} + + + + + Appearance + + + {{ opt }} + + + +
+ + Field offset + + +
+
-
diff --git a/src/app/form-builder/edit-panel/edit-panel.component.scss b/src/app/form-builder/edit-panel/edit-panel.component.scss index f2c15fb..feb7831 100644 --- a/src/app/form-builder/edit-panel/edit-panel.component.scss +++ b/src/app/form-builder/edit-panel/edit-panel.component.scss @@ -1,98 +1,104 @@ -.form { - margin: 20px 10px; - height: calc(100% - 40px); - width: auto; +textarea { + min-height: 28px; +} - mat-slide-toggle { - font-size: 14px; - } +.form { + margin: 16px 8px; + height: calc(100% - 40px); + width: auto; - mat-form-field { - font-size: 14px; - } + mat-slide-toggle { + font-size: 14px; + } + mat-form-field { + font-size: 14px; + } } .full-width { - display: block; - margin: 0 auto; - width: 100%; + display: block; + margin: 0 auto; + width: 100%; } .margin-html { - margin-top: 20px; + margin-top: 6px; } .save-button { - width: 100%; - margin-top: 10px; - margin-bottom: 10px; -} - -.button-text { - color: black !important; + width: 100%; + margin-top: 10px; + margin-bottom: 10px; } .drag-list { - max-width: 100%; - min-height: 60px; - display: block; - background: white; - border-radius: 4px; - overflow: hidden; + max-width: 100%; + min-height: 50px; + display: block; + background: white; + border-radius: 4px; + overflow: hidden; } .drag-box { - margin-top: 8px; - padding: 5px 5px; - color: rgba(0, 0, 0, 0.87); - display: flex; - flex-direction: row; - align-items: center; - justify-content: space-between; - box-sizing: border-box; - cursor: move; - background: white; - font-size: 14px; - height: 67px; + margin-top: 6px; + color: rgba(0, 0, 0, 0.87); + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + box-sizing: border-box; + cursor: move; + background: white; + font-size: 14px; + } .drag-box:hover { - background: #dddddd; + background: #dddddd; } .no-options { - height: 67px; + height: 50px; } .cdk-drag-preview { - box-sizing: border-box; - border-radius: 4px; - box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2), - 0 8px 10px 1px rgba(0, 0, 0, 0.14), - 0 3px 14px 2px rgba(0, 0, 0, 0.12); + box-sizing: border-box; + border-radius: 4px; + box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2), + 0 8px 10px 1px rgba(0, 0, 0, 0.14), + 0 3px 14px 2px rgba(0, 0, 0, 0.12); } .cdk-drag-placeholder { - opacity: 0; + opacity: 0; } .cdk-drag-animating { - transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); + transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); } .drag-box:last-child { - border: none; + border: none; } .drag-list.cdk-drop-list-dragging .drag-box:not(.cdk-drag-placeholder) { - transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); + transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); } .icon-color { - padding-right: 4px; - color: #bbbbbb; + padding-right: 4px; + color: #bbbbbb; } .margin-right8px { - margin-right: 16px; + margin-right: 6px; +} + +.properties { + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + box-sizing: border-box; } diff --git a/src/app/form-builder/edit-panel/edit-panel.component.ts b/src/app/form-builder/edit-panel/edit-panel.component.ts index 5172879..6feece4 100644 --- a/src/app/form-builder/edit-panel/edit-panel.component.ts +++ b/src/app/form-builder/edit-panel/edit-panel.component.ts @@ -2,24 +2,23 @@ import {AfterViewInit, Component, HostListener, OnInit} from '@angular/core'; import {animate, state, style, transition, trigger} from '@angular/animations'; import {GridsterService} from '../gridster/gridster.service'; import { - Appearance, - Component as PetriflowComponent, - DataRef, - DataRefBehavior, - DataType, - DataVariable, - Expression, - I18nString, I18nWithDynamic, - Icon, - IconType, - Option, - Property, - Template, - Transition, - TransitionEvent, - TransitionEventType, + Appearance, + Component as PetriflowComponent, + DataRef, + DataRefBehavior, + DataType, + DataVariable, + I18nString, + I18nWithDynamic, + Icon, + IconType, + Option, + Property, + Template, + Transition, + TransitionEvent, + TransitionEventType } from '@netgrif/petriflow'; -import {ModelService} from '../../modeler/services/model.service'; import {NGX_MAT_DATE_FORMATS} from '@angular-material-components/datetime-picker'; import {DialogRefactorComponent} from '../../dialogs/dialog-refactor/dialog-refactor.component'; import {MatDialog} from '@angular/material/dialog'; @@ -27,456 +26,493 @@ import {Observable} from 'rxjs'; import {FormControl} from '@angular/forms'; import {map, startWith, tap} from 'rxjs/operators'; import {MAT_DATE_FORMATS} from '@angular/material/core'; -import {DATE_FORMAT, DATE_TIME_FORMAT, EnumerationFieldValue} from '@netgrif/components-core'; import {CdkDragDrop, moveItemInArray} from '@angular/cdk/drag-drop'; import {DataFieldUtils} from '../data-field-utils'; import {SelectedTransitionService} from '../../modeler/selected-transition.service'; import {ModelerConfig} from '../../modeler/modeler-config'; +import {ModelService} from '../../modeler/services/model/model.service'; +import {DATE_FORMAT, DATE_TIME_FORMAT, EnumerationFieldValue} from '@netgrif/components-core'; +import {Router} from '@angular/router'; +import {ActionsModeService} from '../../modeler/actions-mode/actions-mode.service'; +import {ActionsMasterDetailService} from '../../modeler/actions-mode/actions-master-detail.setvice'; @Component({ - selector: 'nab-edit-panel', - templateUrl: './edit-panel.component.html', - styleUrls: ['./edit-panel.component.scss'], - animations: [ - trigger('openClose', [ - // ... - state('open', style({ - minWidth: '300px', - })), - state('closed', style({ - minWidth: '180px', - })), - transition('open => closed', [ - animate('0.3s'), - ]), - transition('closed => open', [ - animate('0.3s'), - ]), - ]), - ], - providers: [ - {provide: NGX_MAT_DATE_FORMATS, useValue: DATE_TIME_FORMAT}, - {provide: MAT_DATE_FORMATS, useValue: DATE_FORMAT}, - ], + selector: 'nab-edit-panel', + templateUrl: './edit-panel.component.html', + styleUrls: ['./edit-panel.component.scss'], + animations: [ + trigger('openClose', [ + // ... + state('open', style({ + minWidth: '300px' + })), + state('closed', style({ + minWidth: '180px' + })), + transition('open => closed', [ + animate('0.3s') + ]), + transition('closed => open', [ + animate('0.3s') + ]), + ]), + ], + providers: [ + {provide: NGX_MAT_DATE_FORMATS, useValue: DATE_TIME_FORMAT}, + {provide: MAT_DATE_FORMATS, useValue: DATE_FORMAT} + ] }) export class EditPanelComponent implements OnInit, AfterViewInit { - numOfCols: number; - minOfCols: number; - hover: boolean; - counter: number; - counterMap: number; - transId: string; - filteredOptions: Observable>; - formControlRef: FormControl; - transitionOptions: Array; - - behaviorOptions; - - constructor(public gridsterService: GridsterService, public modelService: ModelService, private dialog: MatDialog, private transitionService: SelectedTransitionService) { - this.transitionOptions = []; - this.formControlRef = new FormControl(); - this.behaviorOptions = [ - DataRefBehavior.EDITABLE, DataRefBehavior.VISIBLE, DataRefBehavior.HIDDEN, DataRefBehavior.FORBIDDEN, - ].map(b => { - return {key: b.toLowerCase(), value: b}; - }); - } - - ngOnInit() { - this.transId = this.transitionService.id; - if (this.transId === null) { - this.numOfCols = ModelerConfig.LAYOUT_DEFAULT_COLS; - this.minOfCols = 1; - this.gridsterService.options.minCols = this.numOfCols; - this.gridsterService.options.maxCols = this.numOfCols; - this.gridsterService.options.maxItemCols = this.numOfCols; - } else { - this.numOfCols = this.modelService.model.getTransition(this.transId)?.dataGroups[0]?.cols; - if (this.numOfCols === undefined) { - this.numOfCols = ModelerConfig.LAYOUT_DEFAULT_COLS; - } - this.minOfCols = 1; - this.gridsterService.placedDataFields.forEach(item => { - if (item.x + item.cols > this.minOfCols) { - this.minOfCols = item.x + item.cols; + numOfCols: number; + minOfCols: number; + hover: boolean; + counter: number; + counterMap: number; + transId: string; + filteredOptions: Observable>; + formControlRef: FormControl; + transitionOptions: Array; + + behaviorOptions; + + constructor(public gridsterService: GridsterService, + public modelService: ModelService, + private dialog: MatDialog, + private transitionService: SelectedTransitionService, + private _router: Router, + private _actionMode: ActionsModeService, + private _actionsMasterDetail: ActionsMasterDetailService) { + // this.transitionOptions = []; + this.formControlRef = new FormControl(); + this.behaviorOptions = [ + DataRefBehavior.EDITABLE, DataRefBehavior.VISIBLE, DataRefBehavior.HIDDEN, DataRefBehavior.FORBIDDEN + ].map(b => { + return {key: b.toLowerCase(), value: b}; + }); + } + + ngOnInit() { + this.transId = this.transitionService.id; + if (this.transId === null) { + this.numOfCols = ModelerConfig.LAYOUT_DEFAULT_COLS; + this.minOfCols = 1; + this.gridsterService.options.minCols = this.numOfCols; + this.gridsterService.options.maxCols = this.numOfCols; + this.gridsterService.options.maxItemCols = this.numOfCols; + } else { + this.numOfCols = this.modelService.model.getTransition(this.transId)?.dataGroups[0]?.cols; + if (this.numOfCols === undefined) { + this.numOfCols = ModelerConfig.LAYOUT_DEFAULT_COLS; + } + this.minOfCols = 1; + this.gridsterService.placedDataFields.forEach(item => { + if (item.x + item.cols > this.minOfCols) { + this.minOfCols = item.x + item.cols; + } + }); + this.gridsterService.options.minCols = this.numOfCols; + this.gridsterService.options.maxCols = this.numOfCols; + this.gridsterService.options.maxItemCols = this.numOfCols; + } + + this.gridsterService.selectedDataFieldStream.subscribe(value => { + if (this.gridsterService.selectedDataField?.dataVariable?.init?.value) { + this.formControlRef.patchValue(this.gridsterService.selectedDataField.dataVariable.init.value); + } else { + this.formControlRef.reset(); + } + }); + this.hover = false; + this.counter = 0; + this.counterMap = 0; + this.transitionOptions = this.createTransOptions(); + this.filteredOptions = this.formControlRef.valueChanges.pipe( + tap(value => { + if (value === '' || value === undefined) { + if (this.gridsterService.selectedDataField?.dataVariable?.init) { + this.gridsterService.selectedDataField.dataVariable.init.value = ''; + } + } + }), + startWith(''), + map(value => this._filter(value)) + ); + } + + get transition(): Transition { + return this.modelService.model.getTransition(this.transitionService.id); + } + + get assignEvent(): TransitionEvent { + return this.getOrCreateEvent(TransitionEventType.ASSIGN); + } + + get finishEvent(): TransitionEvent { + return this.getOrCreateEvent(TransitionEventType.FINISH); + } + + get cancelEvent(): TransitionEvent { + return this.getOrCreateEvent(TransitionEventType.CANCEL); + } + + get delegateEvent(): TransitionEvent { + return this.getOrCreateEvent(TransitionEventType.DELEGATE); + } + + registerChange() { + this.gridsterService.historySave = true; + } + + private getOrCreateEvent(type: TransitionEventType): TransitionEvent { + let event = this.transition.eventSource.getEvent(type); + if (!event) { + event = new TransitionEvent(type, `${this.transition.id}_${type}`); + this.transition.eventSource.addEvent(event); } - }); - this.gridsterService.options.minCols = this.numOfCols; - this.gridsterService.options.maxCols = this.numOfCols; - this.gridsterService.options.maxItemCols = this.numOfCols; - } - - this.gridsterService.selectedDataFieldStream.subscribe(value => { - if (this.gridsterService.selectedDataField?.dataVariable?.init?.value) { - this.formControlRef.patchValue(this.gridsterService.selectedDataField.dataVariable.init.value); - } else { - this.formControlRef.reset(); - } - }); - this.hover = false; - this.counter = 0; - this.counterMap = 0; - this.transitionOptions = this.createTransOptions(); - this.filteredOptions = this.formControlRef.valueChanges.pipe( - tap(value => { - if (value === '' || value === undefined) { - if (this.gridsterService.selectedDataField?.dataVariable?.init) { - this.gridsterService.selectedDataField.dataVariable.init.value = ''; - } + return event; + } + + get dataRef(): DataRef { + return this.gridsterService.selectedDataField.dataRef; + } + + get dataVariable(): DataVariable { + return this.gridsterService.selectedDataField.dataVariable; + } + + get templates(): Array