From 13f5addb6678a5bb233bf9808e245f56e9c12aba Mon Sep 17 00:00:00 2001 From: Paula-Kli Date: Mon, 30 Oct 2023 17:57:49 +0100 Subject: [PATCH 1/3] feat: Show code snipped in diagram cache dialog In order for users to better understand how a personal access token can be helpful the codesnippet from the docs is displayed in the frontend. --- .../model-diagram-dialog.component.css | 5 + .../model-diagram-dialog.component.html | 257 +++++++++++------- .../model-diagram-dialog.component.ts | 42 +++ 3 files changed, 202 insertions(+), 102 deletions(-) diff --git a/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-dialog.component.css b/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-dialog.component.css index de79bc5b7..e82de10f2 100644 --- a/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-dialog.component.css +++ b/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-dialog.component.css @@ -92,3 +92,8 @@ button { mat-divider { margin: 10px 0; } + +pre > code > i { + white-space: pre; + font-style: normal; +} diff --git a/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-dialog.component.html b/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-dialog.component.html index 72ef083a0..407f3805a 100644 --- a/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-dialog.component.html +++ b/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-dialog.component.html @@ -3,7 +3,7 @@ ~ SPDX-License-Identifier: Apache-2.0 -->
-
+

View diagrams

Last update: @@ -13,112 +13,165 @@

View diagrams

}}
- - Search - - search - - {{ filteredDiagrams()?.length }} diagram(s) found: - -
-
- - +
+
+ + + + Learn how to use the diagram cache with capellambse! + + + You can also access the diagrams via our Python library + capellambse. Follow the installation instructions on + [Github] + and then use the code snippet. To authenticate, you have to insert a + personal access token. The token has the same scope as your user. Be + careful with it. +
+

+        model = capellambse.MelodyModel(
+          path="path to the aird file of the model on your machine",
+          diagram_cache={
+            "path": "{{ this.path + "/diagrams/%s"}}",
+            "username": "{{ username }}",
+            "password": "{{ passwordValue !== undefined ? passwordValue : 'You can insert your project token here using the "Insert token" button. The inserted token is valid for 30 days.' }}",
+            }
+          )
+      
+
+ + +
+
+
+ + + Search + + search + + {{ filteredDiagrams()?.length }} diagram(s) found: + +
+
+ + + +
+ error
+ Diagram export has failed.
Please contact your diagram cache + administrator. +
+
+ error
+ Error loading the diagram from the server.
Please try again + later. +
+ If the problem persists, please contact your diagram cache + administrator. +
+
+ +
+ +
+
+
-
- error
- Diagram export has failed.
Please contact your diagram cache - administrator. -
-
- error
- Error loading the diagram from the server.
Please try again later. -
- If the problem persists, please contact your diagram cache - administrator. -
-
- -
- - -
-
- -
-
- Your model doesn't seem to contain diagrams. -
-
- No diagrams for the given filter found. Please remove your search query. -
-
- - +
+
+ Your model doesn't seem to contain diagrams. +
+
+ No diagrams for the given filter found. Please remove your search query. +
+
+ + +
diff --git a/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-dialog.component.ts b/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-dialog.component.ts index cd86370fd..00030ff7f 100644 --- a/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-dialog.component.ts +++ b/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-dialog.component.ts @@ -25,6 +25,9 @@ import { DiagramMetadata, ModelDiagramService, } from 'src/app/projects/models/diagrams/service/model-diagram.service'; +import { ModelService } from 'src/app/projects/models/service/model.service'; +import { UserService } from 'src/app/services/user/user.service'; +import { TokenService } from 'src/app/users/basic-auth-service/basic-auth-token.service'; @Component({ selector: 'app-model-diagram-dialog', @@ -34,6 +37,9 @@ import { export class ModelDiagramDialogComponent { diagramMetadata?: DiagramCacheMetadata; diagrams: Diagrams = {}; + username?: string; + passwordValue?: string; + path?: string; loaderArray = Array(60).fill(0); @@ -55,6 +61,9 @@ export class ModelDiagramDialogComponent { constructor( private modelDiagramService: ModelDiagramService, + private userService: UserService, + private modelService: ModelService, + private tokenService: TokenService, private dialogRef: MatDialogRef, private dialog: MatDialog, @Inject(MAT_DIALOG_DATA) @@ -71,6 +80,27 @@ export class ModelDiagramDialogComponent { this.dialogRef.close(); }, }); + + this.userService + .getCurrentUser() + .subscribe((user) => (this.username = user.name)); + this.path = this.modelService.backendURLFactory( + data.projectSlug, + data.modelSlug, + ); + } + + get codeBlockContent(): string { + return `model = capellambse.MelodyModel( + path="path to the aird file of the model on your machine", + diagram_cache={ + "path": "http://localhost:8000/api/v1/projects/coffee-machine/models/coffee-machine/diagrams/%s", + "username": "${this.username}", + "password": "${ + this.passwordValue ? this.passwordValue : 'yourPassword' + }", + } + )`; } observeVisibleDiagrams() { @@ -155,6 +185,18 @@ export class ModelDiagramDialogComponent { saveAs(response, `${uuid}.svg`); }); } + + async insertToken() { + const expirationDate = new Date(); + expirationDate.setDate(expirationDate.getDate() + 30); + this.tokenService + .createToken( + 'Created in diagram cache dialog', + expirationDate, + 'Diagram-cache', + ) + .subscribe((token) => (this.passwordValue = token.password)); + } } interface Diagrams { From f45fba369df71287e7f7ff5704d347d285bd8bac Mon Sep 17 00:00:00 2001 From: MoritzWeber Date: Thu, 14 Dec 2023 18:19:47 +0100 Subject: [PATCH 2/3] feat: Support Git paths in diagram cache code snippet The commits identifies the primary Git model of a model and adds the information to the code snippet of the diagram cache. In addition, there were some minor/internal changes: - The code snippet code was moved to a new component `ModelDiagramCacheBlockComponent`. - Syntax highlighting was added in the frontend. - A duplication of the code snippet declaration was removed. - Margins and paddings were updated, responsive design was added. - The colors of the code snippet were inverted (white text on dark background) - Information about token revocation was added to the dialog. - A confirmation message for clipboard-copy was added. --- backend/capellacollab/core/metadata.py | 23 +- backend/config/config_template.yaml | 2 +- frontend/.eslintrc.js | 7 +- frontend/angular.json | 3 +- frontend/package-lock.json | 144 +-------- frontend/package.json | 1 + frontend/src/app/app.module.ts | 6 + .../app/general/metadata/metadata.service.ts | 4 + .../model-diagram-code-block.component.html | 54 ++++ .../model-diagram-code-block.component.ts | 124 ++++++++ .../model-diagram-dialog.component.css | 9 - .../model-diagram-dialog.component.html | 274 +++++++----------- .../model-diagram-dialog.component.ts | 56 +--- .../model-overview.component.ts | 2 +- frontend/tailwind.config.js | 1 + 15 files changed, 346 insertions(+), 364 deletions(-) create mode 100644 frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-code-block/model-diagram-code-block.component.html create mode 100644 frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-code-block/model-diagram-code-block.component.ts diff --git a/backend/capellacollab/core/metadata.py b/backend/capellacollab/core/metadata.py index 60dc808ca..f04ed29b0 100644 --- a/backend/capellacollab/core/metadata.py +++ b/backend/capellacollab/core/metadata.py @@ -1,6 +1,8 @@ # SPDX-FileCopyrightText: Copyright DB Netz AG and the capella-collab-manager contributors # SPDX-License-Identifier: Apache-2.0 +import typing as t + import fastapi import pydantic @@ -18,9 +20,15 @@ class Metadata(pydantic.BaseModel): authentication_provider: str | None environment: str | None + host: str | None + port: str | None + protocol: str | None + router = fastapi.APIRouter() -cfg: dict[str, str | None] = config["general"].get("metadata", {}) + +general_cfg: dict[str, t.Any] = config["general"] +metadata_cfg: dict[str, str | None] = general_cfg.get("metadata", {}) @router.get( @@ -30,9 +38,12 @@ class Metadata(pydantic.BaseModel): def get_metadata(): return Metadata( version=capellacollab.__version__, - privacy_policy_url=cfg.get("privacyPolicyURL"), - imprint_url=cfg.get("imprintURL"), - provider=cfg.get("provider"), - authentication_provider=cfg.get("authenticationProvider"), - environment=cfg.get("environment"), + privacy_policy_url=metadata_cfg.get("privacyPolicyURL"), + imprint_url=metadata_cfg.get("imprintURL"), + provider=metadata_cfg.get("provider"), + authentication_provider=metadata_cfg.get("authenticationProvider"), + environment=metadata_cfg.get("environment"), + host=general_cfg.get("host"), + port=str(general_cfg.get("port")), + protocol=general_cfg.get("scheme"), ) diff --git a/backend/config/config_template.yaml b/backend/config/config_template.yaml index 9a7ee18da..c6d356a45 100644 --- a/backend/config/config_template.yaml +++ b/backend/config/config_template.yaml @@ -33,7 +33,7 @@ k8s: general: host: localhost - port: 4200 + port: 8000 scheme: http wildcardHost: False diff --git a/frontend/.eslintrc.js b/frontend/.eslintrc.js index f5fb2ed36..4095a67b2 100644 --- a/frontend/.eslintrc.js +++ b/frontend/.eslintrc.js @@ -70,7 +70,12 @@ module.exports = { parser: "@angular-eslint/template-parser", rules: { "tailwindcss/classnames-order": "off", - "tailwindcss/no-custom-classname": "error", + "tailwindcss/no-custom-classname": [ + "error", + { + whitelist: ["language-python"], + }, + ], "tailwindcss/enforces-negative-arbitrary-values": "error", "tailwindcss/enforces-shorthand": "error", "tailwindcss/no-contradicting-classname": "error", diff --git a/frontend/angular.json b/frontend/angular.json index ca7adad15..5bb481bd1 100644 --- a/frontend/angular.json +++ b/frontend/angular.json @@ -33,7 +33,8 @@ "styles": [ "src/custom-theme.scss", "src/styles.css", - "node_modules/ngx-toastr/toastr.css" + "node_modules/ngx-toastr/toastr.css", + "node_modules/highlight.js/styles/atom-one-dark.css" ], "optimization": { "fonts": false diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 8f4dd38a3..acfd0d7ae 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -23,6 +23,7 @@ "@types/semver": "^7.5.6", "buffer": "^6.0.3", "file-saver": "^2.0.5", + "highlight.js": "^11.9.0", "http-status-codes": "^2.3.0", "ngx-cookie": "^6.0.1", "ngx-skeleton-loader": "^8.1.0", @@ -776,45 +777,6 @@ "yarn": ">= 1.13.0" } }, - "node_modules/@angular-devkit/schematics/node_modules/@angular-devkit/core": { - "version": "17.0.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-17.0.3.tgz", - "integrity": "sha512-SOngD3rKnwZWhhUV68AYlH8M3LRGvF69jnDrYKwtRy1ESqSH7tt+1vexGC290gKvqH7bNMgYv8f5BS1AASRfzw==", - "dev": true, - "dependencies": { - "ajv": "8.12.0", - "ajv-formats": "2.1.1", - "jsonc-parser": "3.2.0", - "picomatch": "3.0.1", - "rxjs": "7.8.1", - "source-map": "0.7.4" - }, - "engines": { - "node": "^18.13.0 || >=20.9.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^3.5.2" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/@angular-devkit/schematics/node_modules/picomatch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-3.0.1.tgz", - "integrity": "sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/@angular-eslint/builder": { "version": "17.1.1", "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-17.1.1.tgz", @@ -977,48 +939,6 @@ "yarn": ">= 1.13.0" } }, - "node_modules/@angular/cli/node_modules/@angular-devkit/architect": { - "version": "0.1700.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1700.3.tgz", - "integrity": "sha512-HUjx7vD16paWXHKHYc2LsSn/kaYbFr2YNnlzuSr9C0kauKS1e7sRpRvtGwQzXfohzgyKi81AAU5uA2KLRGq83w==", - "dev": true, - "dependencies": { - "@angular-devkit/core": "17.0.3", - "rxjs": "7.8.1" - }, - "engines": { - "node": "^18.13.0 || >=20.9.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@angular/cli/node_modules/@angular-devkit/core": { - "version": "17.0.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-17.0.3.tgz", - "integrity": "sha512-SOngD3rKnwZWhhUV68AYlH8M3LRGvF69jnDrYKwtRy1ESqSH7tt+1vexGC290gKvqH7bNMgYv8f5BS1AASRfzw==", - "dev": true, - "dependencies": { - "ajv": "8.12.0", - "ajv-formats": "2.1.1", - "jsonc-parser": "3.2.0", - "picomatch": "3.0.1", - "rxjs": "7.8.1", - "source-map": "0.7.4" - }, - "engines": { - "node": "^18.13.0 || >=20.9.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^3.5.2" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, "node_modules/@angular/cli/node_modules/@npmcli/git": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.3.tgz", @@ -1388,18 +1308,6 @@ "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@angular/cli/node_modules/picomatch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-3.0.1.tgz", - "integrity": "sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/@angular/cli/node_modules/read-package-json": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-7.0.0.tgz", @@ -5474,45 +5382,6 @@ "yarn": ">= 1.13.0" } }, - "node_modules/@schematics/angular/node_modules/@angular-devkit/core": { - "version": "17.0.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-17.0.3.tgz", - "integrity": "sha512-SOngD3rKnwZWhhUV68AYlH8M3LRGvF69jnDrYKwtRy1ESqSH7tt+1vexGC290gKvqH7bNMgYv8f5BS1AASRfzw==", - "dev": true, - "dependencies": { - "ajv": "8.12.0", - "ajv-formats": "2.1.1", - "jsonc-parser": "3.2.0", - "picomatch": "3.0.1", - "rxjs": "7.8.1", - "source-map": "0.7.4" - }, - "engines": { - "node": "^18.13.0 || >=20.9.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^3.5.2" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/@schematics/angular/node_modules/picomatch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-3.0.1.tgz", - "integrity": "sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/@sigstore/bundle": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-1.0.0.tgz", @@ -11272,6 +11141,14 @@ "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==", "dev": true }, + "node_modules/highlight.js": { + "version": "11.9.0", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.9.0.tgz", + "integrity": "sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/hosted-git-info": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", @@ -16117,9 +15994,6 @@ "version": "10.1.0", "inBundle": true, "license": "ISC", - "dependencies": { - "semver": "^7.3.5" - }, "engines": { "node": "14 || >=16.14" } diff --git a/frontend/package.json b/frontend/package.json index 742f26148..8227c4c4b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -28,6 +28,7 @@ "@types/semver": "^7.5.6", "buffer": "^6.0.3", "file-saver": "^2.0.5", + "highlight.js": "^11.9.0", "http-status-codes": "^2.3.0", "ngx-cookie": "^6.0.1", "ngx-skeleton-loader": "^8.1.0", diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index ecb909b4c..b5dfd3f87 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -46,6 +46,10 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { CookieModule } from 'ngx-cookie'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { ToastrModule } from 'ngx-toastr'; +import { + HighlightPipeTransform, + ModelDiagramCodeBlockComponent, +} from 'src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-code-block/model-diagram-code-block.component'; import { BasicAuthTokenComponent } from 'src/app/users/basic-auth-token/basic-auth-token.component'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; @@ -182,6 +186,7 @@ import { UsersProfileComponent } from './users/users-profile/users-profile.compo FormFieldSkeletonLoaderComponent, GitSettingsComponent, HeaderComponent, + HighlightPipeTransform, InitModelComponent, InputDialogComponent, JobRunOverviewComponent, @@ -198,6 +203,7 @@ import { UsersProfileComponent } from './users/users-profile/users-profile.compo ModelComplexityBadgeComponent, ModelDescriptionComponent, ModelDetailComponent, + ModelDiagramCodeBlockComponent, ModelDiagramDialogComponent, ModelDiagramPreviewDialogComponent, ModelOverviewComponent, diff --git a/frontend/src/app/general/metadata/metadata.service.ts b/frontend/src/app/general/metadata/metadata.service.ts index 6f78699a5..61d08dbc9 100644 --- a/frontend/src/app/general/metadata/metadata.service.ts +++ b/frontend/src/app/general/metadata/metadata.service.ts @@ -108,4 +108,8 @@ export interface BackendMetadata { provider: string; authentication_provider: string; environment: string; + + host: string; + port: string; + protocol: string; } diff --git a/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-code-block/model-diagram-code-block.component.html b/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-code-block/model-diagram-code-block.component.html new file mode 100644 index 000000000..34492c302 --- /dev/null +++ b/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-code-block/model-diagram-code-block.component.html @@ -0,0 +1,54 @@ + + + + + + Learn how to use the diagram cache with capellambse! + + +
+ You can also access the diagrams via our Python library + capellambse. Follow the installation instructions on + Githubopen_in_new + + and then use the code snippet. To authenticate, you have to insert a + personal access token. The token has the same scope as your user. Be careful + with it. You can revoke the token in the settings. +
+
+
+ + +
+
diff --git a/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-code-block/model-diagram-code-block.component.ts b/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-code-block/model-diagram-code-block.component.ts new file mode 100644 index 000000000..d128ac623 --- /dev/null +++ b/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-code-block/model-diagram-code-block.component.ts @@ -0,0 +1,124 @@ +/* + * SPDX-FileCopyrightText: Copyright DB Netz AG and the capella-collab-manager contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + AfterViewInit, + Component, + Input, + Pipe, + PipeTransform, +} from '@angular/core'; +import hljs from 'highlight.js'; +import { + BackendMetadata, + MetadataService, +} from 'src/app/general/metadata/metadata.service'; +import { ToastService } from 'src/app/helpers/toast/toast.service'; +import { + Model, + getPrimaryGitModel, +} from 'src/app/projects/models/service/model.service'; +import { Project } from 'src/app/projects/service/project.service'; +import { UserService } from 'src/app/services/user/user.service'; +import { TokenService } from 'src/app/users/basic-auth-service/basic-auth-token.service'; + +@Component({ + selector: 'app-model-diagram-code-block', + styles: [ + '::ng-deep .mat-expansion-indicator::after { border-color: black; }', + ], + templateUrl: './model-diagram-code-block.component.html', +}) +export class ModelDiagramCodeBlockComponent implements AfterViewInit { + passwordValue?: string; + + metadata?: BackendMetadata; + + constructor( + private metadataService: MetadataService, + private userService: UserService, + private tokenService: TokenService, + private toastService: ToastService, + ) { + this.metadataService.backendMetadata.subscribe((metadata) => { + this.metadata = metadata; + }); + } + + @Input({ required: true }) + model!: Model; + + @Input({ required: true }) + project!: Project; + + ngAfterViewInit(): void { + hljs.highlightAll(); + } + + get codeBlockContent(): string { + const basePath = `${this.metadata?.protocol}://${this.metadata?.host}:${this.metadata?.port}`; + let capellaMBSEFlags = + '"path": "",'; + + const primaryGitModel = getPrimaryGitModel(this.model); + if (primaryGitModel) { + capellaMBSEFlags = `path="git+${primaryGitModel.path}", + entrypoint="${primaryGitModel.entrypoint}", + revision="${primaryGitModel.revision}",`; + } + + if (primaryGitModel?.password) { + capellaMBSEFlags += ` + username=input("Please enter the username to access the Git repository."), + password=getpass.getpass("Please enter the password or personal access token to access the Git repository."),`; + } + + return `import capellambse +import getpass + +model = capellambse.MelodyModel( + ${capellaMBSEFlags} + diagram_cache={ + "path": "${basePath}/api/v1/projects/${this.project!.slug}/models/${ + this.model.slug + }/diagrams/%s", + "username": "${this.userService.user?.name}", + "password": "${this.passwordValue ? this.passwordValue : '**************'}", + } +)`; + } + + async insertToken() { + const expirationDate = new Date(); + expirationDate.setDate(expirationDate.getDate() + 30); + this.tokenService + .createToken( + 'Created in diagram cache dialog', + expirationDate, + 'Diagram-cache', + ) + .subscribe((token) => { + this.passwordValue = token.password; + }); + } + + showClipboardMessage(): void { + this.toastService.showSuccess( + 'Code snippet copied to clipboard', + this.passwordValue + ? "The code snipped contains a personal access token for the Collaboration Manager. Be careful with it and don't share it with others!" + : "The code snipped doesn't contain a personal access token. You can insert one with 'Insert token'.", + ); + } +} + +@Pipe({ + name: 'hightlight', +}) +export class HighlightPipeTransform implements PipeTransform { + transform(value: string, language: string): string { + return hljs.highlight(language, value).value; + } +} diff --git a/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-dialog.component.css b/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-dialog.component.css index e82de10f2..ecd1e2caf 100644 --- a/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-dialog.component.css +++ b/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-dialog.component.css @@ -56,10 +56,6 @@ cursor: pointer; } -.header { - height: 150px; -} - button { margin-right: 5px; } @@ -92,8 +88,3 @@ button { mat-divider { margin: 10px 0; } - -pre > code > i { - white-space: pre; - font-style: normal; -} diff --git a/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-dialog.component.html b/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-dialog.component.html index 407f3805a..18c63efc2 100644 --- a/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-dialog.component.html +++ b/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-dialog.component.html @@ -3,175 +3,125 @@ ~ SPDX-License-Identifier: Apache-2.0 -->
-
-

View diagrams

- Last update: - {{ - (diagramMetadata?.last_updated | date: "EE, dd MMM y HH:mm:ss") || - "loading..." - }} +

View diagrams

+
+ Last update: + {{ + (diagramMetadata?.last_updated | date: "EE, dd MMM y HH:mm:ss") || + "loading..." + }} +
-
-
- - - - Learn how to use the diagram cache with capellambse! - - - You can also access the diagrams via our Python library - capellambse. Follow the installation instructions on - [Github] - and then use the code snippet. To authenticate, you have to insert a - personal access token. The token has the same scope as your user. Be - careful with it. -
-

-        model = capellambse.MelodyModel(
-          path="path to the aird file of the model on your machine",
-          diagram_cache={
-            "path": "{{ this.path + "/diagrams/%s"}}",
-            "username": "{{ username }}",
-            "password": "{{ passwordValue !== undefined ? passwordValue : 'You can insert your project token here using the "Insert token" button. The inserted token is valid for 30 days.' }}",
-            }
-          )
-      
-
- - -
-
-
+ - - Search - - search - - {{ filteredDiagrams()?.length }} diagram(s) found: - -
-
- - - -
- error
- Diagram export has failed.
Please contact your diagram cache - administrator. -
-
- error
- Error loading the diagram from the server.
Please try again - later. -
- If the problem persists, please contact your diagram cache - administrator. -
-
- -
- -
-
-
+ + Search + + search + + {{ filteredDiagrams()?.length }} diagram(s) found: + +
+ + -
-
- Your model doesn't seem to contain diagrams. -
-
- No diagrams for the given filter found. Please remove your search query. -
-
- - -
+
+ error
+ Diagram export has failed.
Please contact your diagram cache + administrator. +
+
+ error
+ Error loading the diagram from the server.
Please try again later. +
+ If the problem persists, please contact your diagram cache + administrator. +
+
+ +
+ + +
+
+ +
+
+ Your model doesn't seem to contain diagrams. +
+
+ No diagrams for the given filter found. Please remove your search query. +
+
+ +
diff --git a/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-dialog.component.ts b/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-dialog.component.ts index 00030ff7f..0ab2985d1 100644 --- a/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-dialog.component.ts +++ b/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-dialog.component.ts @@ -12,8 +12,8 @@ import { } from '@angular/core'; import { MatDialog, - MatDialogRef, MAT_DIALOG_DATA, + MatDialogRef, } from '@angular/material/dialog'; import { saveAs } from 'file-saver'; import { @@ -25,9 +25,8 @@ import { DiagramMetadata, ModelDiagramService, } from 'src/app/projects/models/diagrams/service/model-diagram.service'; -import { ModelService } from 'src/app/projects/models/service/model.service'; -import { UserService } from 'src/app/services/user/user.service'; -import { TokenService } from 'src/app/users/basic-auth-service/basic-auth-token.service'; +import { Model } from 'src/app/projects/models/service/model.service'; +import { Project } from 'src/app/projects/service/project.service'; @Component({ selector: 'app-model-diagram-dialog', @@ -37,9 +36,6 @@ import { TokenService } from 'src/app/users/basic-auth-service/basic-auth-token. export class ModelDiagramDialogComponent { diagramMetadata?: DiagramCacheMetadata; diagrams: Diagrams = {}; - username?: string; - passwordValue?: string; - path?: string; loaderArray = Array(60).fill(0); @@ -61,16 +57,13 @@ export class ModelDiagramDialogComponent { constructor( private modelDiagramService: ModelDiagramService, - private userService: UserService, - private modelService: ModelService, - private tokenService: TokenService, - private dialogRef: MatDialogRef, private dialog: MatDialog, + private dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) - public data: { modelSlug: string; projectSlug: string }, + public data: { model: Model; project: Project }, ) { this.modelDiagramService - .getDiagramMetadata(this.data.projectSlug, this.data.modelSlug) + .getDiagramMetadata(this.data.project.slug, this.data.model.slug) .subscribe({ next: (diagramMetadata) => { this.diagramMetadata = diagramMetadata; @@ -80,27 +73,6 @@ export class ModelDiagramDialogComponent { this.dialogRef.close(); }, }); - - this.userService - .getCurrentUser() - .subscribe((user) => (this.username = user.name)); - this.path = this.modelService.backendURLFactory( - data.projectSlug, - data.modelSlug, - ); - } - - get codeBlockContent(): string { - return `model = capellambse.MelodyModel( - path="path to the aird file of the model on your machine", - diagram_cache={ - "path": "http://localhost:8000/api/v1/projects/coffee-machine/models/coffee-machine/diagrams/%s", - "username": "${this.username}", - "password": "${ - this.passwordValue ? this.passwordValue : 'yourPassword' - }", - } - )`; } observeVisibleDiagrams() { @@ -133,7 +105,7 @@ export class ModelDiagramDialogComponent { if (!this.diagrams[uuid]) { this.diagrams[uuid] = { loading: true, content: undefined }; this.modelDiagramService - .getDiagram(this.data.projectSlug, this.data.modelSlug, uuid) + .getDiagram(this.data.project.slug, this.data.model.slug, uuid) .subscribe({ next: (response: Blob) => { const reader = new FileReader(); @@ -180,23 +152,11 @@ export class ModelDiagramDialogComponent { downloadDiagram(uuid: string) { this.modelDiagramService - .getDiagram(this.data.projectSlug, this.data.modelSlug, uuid) + .getDiagram(this.data.project.slug, this.data.model.slug, uuid) .subscribe((response: Blob) => { saveAs(response, `${uuid}.svg`); }); } - - async insertToken() { - const expirationDate = new Date(); - expirationDate.setDate(expirationDate.getDate() + 30); - this.tokenService - .createToken( - 'Created in diagram cache dialog', - expirationDate, - 'Diagram-cache', - ) - .subscribe((token) => (this.passwordValue = token.password)); - } } interface Diagrams { diff --git a/frontend/src/app/projects/project-detail/model-overview/model-overview.component.ts b/frontend/src/app/projects/project-detail/model-overview/model-overview.component.ts index e2b46877a..071c5220c 100644 --- a/frontend/src/app/projects/project-detail/model-overview/model-overview.component.ts +++ b/frontend/src/app/projects/project-detail/model-overview/model-overview.component.ts @@ -85,7 +85,7 @@ export class ModelOverviewComponent implements OnInit { 'w-full', 'h-full', ], - data: { modelSlug: model.slug, projectSlug: this.project?.slug }, + data: { model: model, project: this.project }, }); } diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js index ddcbbd9c4..23f8c73cc 100644 --- a/frontend/tailwind.config.js +++ b/frontend/tailwind.config.js @@ -15,6 +15,7 @@ module.exports = { success: "var(--success-color)", hover: "var(--hover-color)", archived: "#D1D5DB", + url: "#2563eb", }, spacing: { button: "0.5rem", From 89b8ebfc5ae4fa2e8446ce0270152d72849b8f9d Mon Sep 17 00:00:00 2001 From: MoritzWeber Date: Fri, 15 Dec 2023 14:55:56 +0100 Subject: [PATCH 3/3] chore: Replace CSS rules with TailwindCSS in diagram dialog --- .../model-diagram-dialog.component.css | 72 ------------------- .../model-diagram-dialog.component.html | 32 ++++----- 2 files changed, 15 insertions(+), 89 deletions(-) diff --git a/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-dialog.component.css b/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-dialog.component.css index ecd1e2caf..0b3bde5b9 100644 --- a/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-dialog.component.css +++ b/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-dialog.component.css @@ -3,29 +3,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -.diagrams { - height: calc(80vh - 170px); - word-wrap: break-word; -} - -.diagram-card { - display: flex; - flex-direction: column; - justify-content: space-between; - flex-grow: 1; - flex-basis: calc(30% - 20px); -} - -.uuid { - color: grey; -} - -.loader { - margin: 10px; - flex-grow: 1; - flex-basis: calc(30% - 20px); -} - .diagram-error { border-radius: 5px; border: solid lightgray; @@ -39,52 +16,3 @@ justify-content: center; align-items: center; } - -.diagram-error-icon { - color: darkred; - transform: scale(2); -} - -.diagram { - height: 200px; - width: 100%; - margin-bottom: 15px; - touch-action: auto !important; -} - -.diagram:hover { - cursor: pointer; -} - -button { - margin-right: 5px; -} - -.diagram-metadata { - overflow-y: hidden; -} - -.download-button { - width: 100%; - margin: 5px 0; -} - -.list-item { - display: flex; - justify-content: space-between; - flex-wrap: nowrap; -} - -#search { - margin-top: 10px; - width: 100%; - padding-bottom: 5px; -} - -.diagram-name { - font-size: 1.25em; -} - -mat-divider { - margin: 10px 0; -} diff --git a/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-dialog.component.html b/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-dialog.component.html index 18c63efc2..ab9ca391c 100644 --- a/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-dialog.component.html +++ b/frontend/src/app/projects/models/diagrams/model-diagram-dialog/model-diagram-dialog.component.html @@ -17,11 +17,7 @@

View diagrams

[model]="data.model" > - + Search View diagrams
View diagrams (click)="openModelDiagramPreviewDialog(diagram)" matTooltip="Open preview" *ngIf="diagram.success && diagrams[diagram.uuid]?.content" - class="diagram" + class="mb-2 h-[200px] w-full !touch-auto hover:cursor-pointer" [src]="diagrams[diagram.uuid].content" />
- error
+ error
Diagram export has failed.
Please contact your diagram cache administrator.
@@ -75,20 +73,20 @@

View diagrams

" class="diagram-error" > - error
+ error
Error loading the diagram from the server.
Please try again later.
If the problem persists, please contact your diagram cache administrator.
-
-