oip-common 0.0.6 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/ng-package.json +19 -0
  2. package/package.json +19 -38
  3. package/src/api/FolderModule.ts +124 -0
  4. package/src/api/Menu.ts +134 -0
  5. package/src/api/Module.ts +92 -0
  6. package/src/api/Security.ts +40 -0
  7. package/src/api/Service.ts +57 -0
  8. package/src/api/data-contracts.ts +186 -0
  9. package/src/api/http-client.ts +276 -0
  10. package/src/components/app-configurator.component.ts +491 -0
  11. package/src/components/app-floating-configurator.component.ts +47 -0
  12. package/src/components/app-modules.component.ts +144 -0
  13. package/src/components/app.layout.component.ts +130 -0
  14. package/src/components/auth/access/access.component.ts +42 -0
  15. package/src/components/auth/error/error.component.ts +42 -0
  16. package/src/components/auth/login/login.component.ts +120 -0
  17. package/src/components/auth/unauthorized/unauthorized.component.ts +51 -0
  18. package/src/components/base-module.component.ts +258 -0
  19. package/src/components/config.component.ts +131 -0
  20. package/src/components/db-migration/db-migration.component.ts +164 -0
  21. package/src/components/db-migration.component.ts +156 -0
  22. package/src/components/footer.component.ts +17 -0
  23. package/src/components/logo.component.ts +34 -0
  24. package/src/components/menu/menu-item-create-dialog.component.ts +119 -0
  25. package/src/components/menu/menu-item-edit-dialog.component.ts +124 -0
  26. package/src/components/menu/menu-item.component.ts +295 -0
  27. package/src/components/menu/menu.component.ts +85 -0
  28. package/src/components/notfound.component.ts +31 -0
  29. package/src/components/profile.component.ts +44 -0
  30. package/src/components/security.component.ts +102 -0
  31. package/src/components/sidebar.component.ts +12 -0
  32. package/src/components/top-bar.component.ts +147 -0
  33. package/src/dtos/context-menu-item.dto.ts +23 -0
  34. package/src/dtos/edit-module-instance.dto.ts +8 -0
  35. package/src/dtos/no-settings.dto.ts +4 -0
  36. package/src/dtos/put-security.dto.ts +6 -0
  37. package/src/dtos/security.dto.ts +6 -0
  38. package/src/dtos/top-bar.dto.ts +13 -0
  39. package/src/events/menu-change.event.ts +23 -0
  40. package/src/helpers/date.helper.ts +94 -0
  41. package/src/intercepts/i18n-intercept.service.ts +13 -0
  42. package/src/modules/http-loader.factory.ts +40 -0
  43. package/src/modules/secure.pipe.ts +19 -0
  44. package/src/public-api.ts +42 -0
  45. package/src/services/app-title.service.ts +22 -0
  46. package/src/services/app.layout.service.ts +236 -0
  47. package/src/services/app.menu.service.ts +64 -0
  48. package/src/services/auth.service.ts +58 -0
  49. package/src/services/base-data.service.ts +74 -0
  50. package/src/services/l10n.service.ts +71 -0
  51. package/src/services/msg.service.ts +76 -0
  52. package/src/services/security-data.service.ts +19 -0
  53. package/src/services/security-storage.service.ts +21 -0
  54. package/src/services/security.service.ts +116 -0
  55. package/src/services/top-bar.service.ts +44 -0
  56. package/src/services/user.service.ts +77 -0
  57. package/src/test.ts +11 -0
  58. package/src/user-api/UserProfile.ts +85 -0
  59. package/src/user-api/data-contracts.ts +42 -0
  60. package/src/user-api/http-client.ts +253 -0
  61. package/templates/api.ejs +30 -0
  62. package/templates/data-contract-jsdoc.ejs +37 -0
  63. package/templates/data-contracts.ejs +52 -0
  64. package/templates/enum-data-contract.ejs +12 -0
  65. package/templates/http-client.ejs +245 -0
  66. package/templates/interface-data-contract.ejs +10 -0
  67. package/templates/object-field-jsdoc.ejs +28 -0
  68. package/templates/procedure-call.ejs +100 -0
  69. package/templates/route-docs.ejs +29 -0
  70. package/templates/route-name.ejs +42 -0
  71. package/templates/route-type.ejs +23 -0
  72. package/templates/route-types.ejs +18 -0
  73. package/templates/type-data-contract.ejs +15 -0
  74. package/tsconfig.lib.json +12 -0
  75. package/tsconfig.lib.prod.json +10 -0
  76. package/tsconfig.spec.json +9 -0
  77. /package/{assets → src/assets}/demo/code.scss +0 -0
  78. /package/{assets → src/assets}/demo/demo.scss +0 -0
  79. /package/{assets → src/assets}/demo/flags/flags.scss +0 -0
  80. /package/{assets → src/assets}/demo/flags/flags_responsive.png +0 -0
  81. /package/{assets → src/assets}/demo/images/access/asset-access.svg +0 -0
  82. /package/{assets → src/assets}/demo/images/error/asset-error.svg +0 -0
  83. /package/{assets → src/assets}/demo/images/flag/flag_placeholder.png +0 -0
  84. /package/{assets → src/assets}/favicon.svg +0 -0
  85. /package/{assets → src/assets}/i18n/app-modules.en.json +0 -0
  86. /package/{assets → src/assets}/i18n/app-modules.ru.json +0 -0
  87. /package/{assets → src/assets}/i18n/config.en.json +0 -0
  88. /package/{assets → src/assets}/i18n/config.ru.json +0 -0
  89. /package/{assets → src/assets}/layout/_core.scss +0 -0
  90. /package/{assets → src/assets}/layout/_footer.scss +0 -0
  91. /package/{assets → src/assets}/layout/_logo.scss +0 -0
  92. /package/{assets → src/assets}/layout/_main.scss +0 -0
  93. /package/{assets → src/assets}/layout/_menu.scss +0 -0
  94. /package/{assets → src/assets}/layout/_mixins.scss +0 -0
  95. /package/{assets → src/assets}/layout/_preloading.scss +0 -0
  96. /package/{assets → src/assets}/layout/_responsive.scss +0 -0
  97. /package/{assets → src/assets}/layout/_topbar.scss +0 -0
  98. /package/{assets → src/assets}/layout/_typography.scss +0 -0
  99. /package/{assets → src/assets}/layout/_utils.scss +0 -0
  100. /package/{assets → src/assets}/layout/layout.scss +0 -0
  101. /package/{assets → src/assets}/layout/variables/_common.scss +0 -0
  102. /package/{assets → src/assets}/layout/variables/_dark.scss +0 -0
  103. /package/{assets → src/assets}/layout/variables/_light.scss +0 -0
  104. /package/{assets → src/assets}/oip-common.scss +0 -0
  105. /package/{assets → src/assets}/tailwind.css +0 -0
@@ -0,0 +1,131 @@
1
+ import { Component, inject, OnInit } from '@angular/core';
2
+ import { ProfileComponent } from './profile.component';
3
+ import { Fluid } from 'primeng/fluid';
4
+ import { Tooltip } from 'primeng/tooltip';
5
+ import { FormsModule } from '@angular/forms';
6
+ import { Select } from 'primeng/select';
7
+ import { TableModule } from 'primeng/table';
8
+ import { LayoutService } from '../services/app.layout.service';
9
+ import { UserService } from '../services/user.service';
10
+ import { ToggleSwitchModule } from 'primeng/toggleswitch';
11
+ import { RouterLink } from '@angular/router';
12
+ import { SecurityService } from '../services/security.service';
13
+ import { MenuService } from '../services/app.menu.service';
14
+ import { Button } from 'primeng/button';
15
+ import { L10nService } from '../services/l10n.service';
16
+ import { SelectItem } from 'primeng/api';
17
+
18
+ interface L10n {
19
+ menu: string;
20
+ all: string;
21
+ profile: string;
22
+ photo: string;
23
+ usePhoto256x256Pixel: string;
24
+ selectLanguage: string;
25
+ moduleManagement: string;
26
+ localization: string;
27
+ goTo: string;
28
+ }
29
+
30
+ @Component({
31
+ selector: 'app-config',
32
+ template: `
33
+ <p-fluid>
34
+ <div class="flex flex-col md:flex-row gap-4">
35
+ <div class="md:w-1/2">
36
+ <div class="card flex flex-col gap-4">
37
+ <div class="font-semibold text-xl">{{ l10n.profile }}</div>
38
+ <div class="flex justify-content-end flex-wrap">
39
+ {{ userService.userName }}
40
+ </div>
41
+ <label>
42
+ {{ l10n.photo }}
43
+ <span
44
+ class="pi pi-question-circle"
45
+ pTooltip="{{ l10n.usePhoto256x256Pixel }}"
46
+ tooltipPosition="right"></span>
47
+ </label>
48
+ <div class="flex justify-content-end flex-wrap">
49
+ <user-profile></user-profile>
50
+ </div>
51
+ </div>
52
+ </div>
53
+ <div class="md:w-1/2">
54
+ <div class="card flex flex-col gap-4">
55
+ <div class="font-semibold text-xl">{{ l10n.localization }}</div>
56
+ <label> {{ l10n.selectLanguage }} </label>
57
+ <div class="flex justify-content-end flex-wrap">
58
+ <p-select
59
+ class="w-full md:w-56"
60
+ id="oip-app-config-language-select"
61
+ optionLabel="label"
62
+ optionValue="value"
63
+ [options]="languages"
64
+ [(ngModel)]="selectedLanguage"
65
+ (onChange)="changeLanguage()" />
66
+ </div>
67
+ </div>
68
+ </div>
69
+ @if (securityService.isAdmin) {
70
+ <div class="md:w-1/2">
71
+ <div class="card flex flex-col gap-4">
72
+ <div class="font-semibold text-xl">{{ l10n.menu }}</div>
73
+ <div class="flex items-center gap-2">
74
+ <label for="oip-app-config-admin-mode">{{ l10n.all }}</label>
75
+ <p-toggle-switch
76
+ id="oip-app-config-admin-mode"
77
+ [(ngModel)]="menuService.adminMode"
78
+ (onChange)="onSwitchChange()"></p-toggle-switch>
79
+ </div>
80
+ <div class="flex items-center gap-2">
81
+ <label for="oip-app-config-admin-mode">{{ l10n.moduleManagement }}</label>
82
+ <p-button icon="pi pi-cog" label="{{ l10n.goTo }}" routerLink="/modules" />
83
+ </div>
84
+ </div>
85
+ </div>
86
+ }
87
+ </div>
88
+ </p-fluid>
89
+ `,
90
+ imports: [ProfileComponent, Fluid, Tooltip, FormsModule, Select, TableModule, ToggleSwitchModule, RouterLink, Button]
91
+ })
92
+ export class ConfigComponent implements OnInit {
93
+ private readonly layoutService = inject(LayoutService);
94
+ private readonly l10nService = inject(L10nService);
95
+ protected readonly userService = inject(UserService);
96
+ protected readonly securityService = inject(SecurityService);
97
+ protected readonly menuService = inject(MenuService);
98
+ protected l10n = {} as L10n;
99
+
100
+ selectedLanguage: string;
101
+ languages: SelectItem<string>[] = [
102
+ { value: 'en', label: 'English' },
103
+ { value: 'ru', label: 'Русский' }
104
+ ];
105
+
106
+ constructor() {
107
+ this.selectedLanguage = this.layoutService.language();
108
+ }
109
+
110
+ async ngOnInit() {
111
+ (await this.l10nService.get('config')).subscribe((l10n) => {
112
+ this.l10n = l10n;
113
+ });
114
+ }
115
+
116
+ /**
117
+ * Changes the application's language.
118
+ * @return {void}
119
+ */
120
+ changeLanguage(): void {
121
+ this.layoutService.layoutConfig.update((config) => ({
122
+ ...config,
123
+ language: this.selectedLanguage
124
+ }));
125
+ this.l10nService.use(this.selectedLanguage);
126
+ }
127
+
128
+ async onSwitchChange(): Promise<void> {
129
+ await this.menuService.loadMenu();
130
+ }
131
+ }
@@ -0,0 +1,164 @@
1
+ import { Component, inject, OnDestroy, OnInit } from '@angular/core';
2
+ import { TagModule } from 'primeng/tag';
3
+ import { ConfirmationService, SharedModule } from 'primeng/api';
4
+ import { TableModule } from 'primeng/table';
5
+ import { InputTextModule } from 'primeng/inputtext';
6
+ import { TextareaModule } from 'primeng/textarea';
7
+ import { ButtonModule } from 'primeng/button';
8
+ import { FormsModule } from '@angular/forms';
9
+ import { ConfirmDialog } from 'primeng/confirmdialog';
10
+ import { NgIf } from '@angular/common';
11
+ import { Tooltip } from 'primeng/tooltip';
12
+ import { ActivatedRoute } from '@angular/router';
13
+ import { BaseModuleComponent } from '../base-module.component';
14
+ import { NoSettingsDto } from '../../dtos/no-settings.dto';
15
+ import { SecurityComponent } from '../security.component';
16
+
17
+ export interface MigrationDto {
18
+ name: string;
19
+ applied: boolean;
20
+ pending: boolean;
21
+ exist: boolean;
22
+ }
23
+
24
+ export interface ApplyMigrationRequest {
25
+ name: string;
26
+ }
27
+
28
+ @Component({
29
+ imports: [
30
+ TableModule,
31
+ SharedModule,
32
+ TagModule,
33
+ InputTextModule,
34
+ TextareaModule,
35
+ ButtonModule,
36
+ FormsModule,
37
+ ConfirmDialog,
38
+ NgIf,
39
+ SecurityComponent,
40
+ Tooltip
41
+ ],
42
+ selector: 'crypt',
43
+ template: `
44
+ <div *ngIf="isContent" class="card" style="height: 100%">
45
+ <p-confirmDialog />
46
+ <div>
47
+ <h5>Migration manager</h5>
48
+ <div class="flex flex-row gap-2">
49
+ <p-button
50
+ icon="pi pi-refresh"
51
+ pTooltip="Refresh"
52
+ severity="secondary"
53
+ tooltipPosition="bottom"
54
+ [outlined]="true"
55
+ (click)="refreshAction()" />
56
+ <p-button
57
+ icon="pi pi-filter-slash"
58
+ pTooltip="Clean filter"
59
+ severity="secondary"
60
+ tooltipPosition="bottom"
61
+ [outlined]="true"
62
+ (click)="dt.clear()" />
63
+ </div>
64
+ <div>
65
+ <p-table #dt dataKey="name" editMode="row" size="small" [scrollable]="true" [value]="data">
66
+ <ng-template let-columns pTemplate="header">
67
+ <tr>
68
+ <th pSortableColumn="name" scope="col">
69
+ Migration name
70
+ <p-columnFilter display="menu" field="name" type="text" />
71
+ </th>
72
+ <th scope="col">Applied</th>
73
+ <th scope="col">Exist</th>
74
+ <th>Pending</th>
75
+ <th scope="col"></th>
76
+ </tr>
77
+ </ng-template>
78
+
79
+ <ng-template #body let-columns="columns" let-editing="editing" let-ri="rowIndex" let-rowData>
80
+ <tr [pEditableRow]="rowData">
81
+ <td>
82
+ {{ rowData.name }}
83
+ </td>
84
+ <td>
85
+ <p-button
86
+ *ngIf="rowData.applied"
87
+ icon="pi pi-check"
88
+ severity="success"
89
+ [rounded]="true"
90
+ [text]="true">
91
+ </p-button>
92
+ </td>
93
+ <td>
94
+ <p-button *ngIf="rowData.exist" icon="pi pi-check" severity="success" [rounded]="true" [text]="true">
95
+ </p-button>
96
+ </td>
97
+ <td>
98
+ <p-button
99
+ *ngIf="rowData.pending"
100
+ icon="pi pi-check"
101
+ severity="success"
102
+ [rounded]="true"
103
+ [text]="true">
104
+ </p-button>
105
+ </td>
106
+ <td>
107
+ <p-button
108
+ icon="pi pi-bolt"
109
+ pCancelEditableRow
110
+ pTooltip="Apply migration"
111
+ severity="secondary"
112
+ tooltipPosition="left"
113
+ [rounded]="true"
114
+ [text]="true"
115
+ (click)="applyMigration(rowData)">
116
+ </p-button>
117
+ </td>
118
+ </tr>
119
+ </ng-template>
120
+ </p-table>
121
+ </div>
122
+ </div>
123
+ </div>
124
+ <security *ngIf="isSecurity" [controller]="controller" [id]="id"></security>
125
+ `,
126
+ providers: [ConfirmationService]
127
+ })
128
+ export class DbMigrationComponent
129
+ extends BaseModuleComponent<NoSettingsDto, NoSettingsDto>
130
+ implements OnInit, OnDestroy
131
+ {
132
+ private readonly activatedRoute = inject(ActivatedRoute);
133
+ controller: string = '';
134
+ data: MigrationDto[];
135
+
136
+ async ngOnInit() {
137
+ this.activatedRoute.url.subscribe((url) => {
138
+ this.controller = url[0].toString();
139
+ });
140
+ this.appTitleService.setTitle('Db Migration');
141
+ await super.ngOnInit();
142
+ await this.refreshAction();
143
+ }
144
+
145
+ async refreshAction() {
146
+ this.getData()
147
+ .then((response) => {
148
+ this.data = response;
149
+ })
150
+ .catch((error) => {
151
+ console.log(error);
152
+ this.msgService.error('Error refreshing database');
153
+ });
154
+ }
155
+
156
+ async getData() {
157
+ return this.baseDataService.sendRequest<MigrationDto[]>(`api/${this.controller}/get-migrations`, 'GET');
158
+ }
159
+
160
+ async applyMigration(rowData: MigrationDto) {
161
+ const request = { name: rowData.name } as ApplyMigrationRequest;
162
+ return this.baseDataService.sendRequest(`api/${this.controller}/apply-migration`, 'POST', request);
163
+ }
164
+ }
@@ -0,0 +1,156 @@
1
+ import { Component, OnDestroy, OnInit } from '@angular/core';
2
+ import { TagModule } from 'primeng/tag';
3
+ import { ConfirmationService, SharedModule } from 'primeng/api';
4
+ import { TableModule } from 'primeng/table';
5
+ import { InputTextModule } from 'primeng/inputtext';
6
+ import { TextareaModule } from 'primeng/textarea';
7
+ import { ButtonModule } from 'primeng/button';
8
+ import { FormsModule } from '@angular/forms';
9
+ import { ConfirmDialog } from 'primeng/confirmdialog';
10
+ import { NgIf } from '@angular/common';
11
+ import { Tooltip } from 'primeng/tooltip';
12
+ import { BaseModuleComponent } from './base-module.component';
13
+ import { NoSettingsDto } from '../dtos/no-settings.dto';
14
+ import { SecurityComponent } from './security.component';
15
+
16
+ export interface MigrationDto {
17
+ name: string;
18
+ applied: boolean;
19
+ pending: boolean;
20
+ exist: boolean;
21
+ }
22
+
23
+ export interface ApplyMigrationRequest {
24
+ name: string;
25
+ }
26
+
27
+ @Component({
28
+ imports: [
29
+ TableModule,
30
+ SharedModule,
31
+ TagModule,
32
+ InputTextModule,
33
+ TextareaModule,
34
+ ButtonModule,
35
+ FormsModule,
36
+ ConfirmDialog,
37
+ NgIf,
38
+ SecurityComponent,
39
+ Tooltip
40
+ ],
41
+ selector: 'db-migration',
42
+ template: `
43
+ <div *ngIf="isContent" class="card" style="height: 100%">
44
+ <p-confirmDialog />
45
+ <div>
46
+ <h5>Migration manager</h5>
47
+ <div class="flex flex-row gap-2">
48
+ <p-button
49
+ icon="pi pi-refresh"
50
+ pTooltip="Refresh"
51
+ severity="secondary"
52
+ tooltipPosition="bottom"
53
+ [outlined]="true"
54
+ (click)="refreshAction()" />
55
+ <p-button
56
+ icon="pi pi-filter-slash"
57
+ pTooltip="Clean filter"
58
+ severity="secondary"
59
+ tooltipPosition="bottom"
60
+ [outlined]="true"
61
+ (click)="dt.clear()" />
62
+ </div>
63
+ <div>
64
+ <p-table #dt dataKey="name" editMode="row" size="small" [scrollable]="true" [value]="data">
65
+ <ng-template let-columns pTemplate="header">
66
+ <tr>
67
+ <th pSortableColumn="name" scope="col">
68
+ Migration name
69
+ <p-columnFilter display="menu" field="name" type="text" />
70
+ </th>
71
+ <th scope="col">Applied</th>
72
+ <th scope="col">Exist</th>
73
+ <th>Pending</th>
74
+ <th scope="col"></th>
75
+ </tr>
76
+ </ng-template>
77
+
78
+ <ng-template #body let-columns="columns" let-editing="editing" let-ri="rowIndex" let-rowData>
79
+ <tr [pEditableRow]="rowData">
80
+ <td>
81
+ {{ rowData.name }}
82
+ </td>
83
+ <td>
84
+ <p-button
85
+ *ngIf="rowData.applied"
86
+ icon="pi pi-check"
87
+ severity="success"
88
+ [rounded]="true"
89
+ [text]="true">
90
+ </p-button>
91
+ </td>
92
+ <td>
93
+ @if (rowData.exist) {
94
+ <p-button icon="pi pi-check" severity="success" [rounded]="true" [text]="true" />
95
+ }
96
+ </td>
97
+ <td>
98
+ @if (rowData.pending) {
99
+ <p-button icon="pi pi-check" severity="success" [rounded]="true" [text]="true"></p-button>
100
+ }
101
+ </td>
102
+ <td>
103
+ <p-button
104
+ icon="pi pi-bolt"
105
+ pCancelEditableRow
106
+ pTooltip="Apply migration"
107
+ severity="secondary"
108
+ tooltipPosition="left"
109
+ [rounded]="true"
110
+ [text]="true"
111
+ (click)="applyMigration(rowData)">
112
+ </p-button>
113
+ </td>
114
+ </tr>
115
+ </ng-template>
116
+ </p-table>
117
+ </div>
118
+ </div>
119
+ </div>
120
+ @if (isSecurity) {
121
+ <security [controller]="controller" [id]="id" />
122
+ }
123
+ `,
124
+ providers: [ConfirmationService]
125
+ })
126
+ export class DbMigrationComponent
127
+ extends BaseModuleComponent<NoSettingsDto, NoSettingsDto>
128
+ implements OnInit, OnDestroy
129
+ {
130
+ data: MigrationDto[];
131
+
132
+ async ngOnInit() {
133
+ await super.ngOnInit();
134
+ await this.refreshAction();
135
+ }
136
+
137
+ async refreshAction() {
138
+ this.getData()
139
+ .then((response) => {
140
+ this.data = response;
141
+ })
142
+ .catch((error) => {
143
+ console.log(error);
144
+ this.msgService.error('Error refreshing database');
145
+ });
146
+ }
147
+
148
+ async getData() {
149
+ return this.baseDataService.sendRequest<MigrationDto[]>(`api/${this.controller}/get-migrations`, 'GET');
150
+ }
151
+
152
+ async applyMigration(rowData: MigrationDto) {
153
+ const request = { name: rowData.name } as ApplyMigrationRequest;
154
+ return this.baseDataService.sendRequest(`api/${this.controller}/apply-migration`, 'POST', request);
155
+ }
156
+ }
@@ -0,0 +1,17 @@
1
+ import { Component } from '@angular/core';
2
+ import { LogoComponent } from './logo.component';
3
+
4
+ @Component({
5
+ selector: 'app-footer',
6
+ template: `
7
+ <div class="layout-footer">
8
+ <logo class="mr-2" height="18" width="18"></logo>
9
+ <span class="font-medium">OIP</span>
10
+ </div>
11
+ `,
12
+ standalone: true,
13
+ imports: [LogoComponent]
14
+ })
15
+ export class FooterComponent {
16
+ constructor() {}
17
+ }
@@ -0,0 +1,34 @@
1
+ import { Component, Input } from '@angular/core';
2
+
3
+ @Component({
4
+ selector: 'logo',
5
+ standalone: true,
6
+ template: `
7
+ <svg
8
+ viewBox="0.8516 1.7159 60.0074 64.7142"
9
+ xmlns="http://www.w3.org/2000/svg"
10
+ [attr.height]="height + 'px'"
11
+ [attr.width]="width + 'px'">
12
+ <path
13
+ class="primary-logo-color"
14
+ d="M -130.45 -104.78 C -130.45 -105.9 -130.43 -107.01 -130.45 -108.13 C -130.49 -108.52 -130.28 -108.9 -129.92 -109.07 C -125.87 -111.4 -121.82 -113.74 -117.77 -116.08 C -115.7 -117.26 -113.63 -118.45 -111.58 -119.67 C -111.26 -119.89 -110.83 -119.89 -110.51 -119.67 C -101.66 -114.53 -92.787 -109.41 -83.915 -104.29 C -83.752 -104.2 -83.479 -104.16 -83.475 -103.94 C -83.472 -103.72 -83.766 -103.65 -83.947 -103.54 C -86.326 -102.16 -88.716 -100.79 -91.092 -99.39 C -91.377 -99.18 -91.761 -99.18 -92.046 -99.39 C -98.211 -102.98 -104.38 -106.55 -110.56 -110.12 C -110.85 -110.33 -111.23 -110.33 -111.52 -110.12 C -114.88 -108.16 -118.25 -106.22 -121.63 -104.28 C -122.01 -104.11 -122.24 -103.71 -122.2 -103.3 C -122.18 -101.11 -122.2 -98.922 -122.2 -96.736 C -122.19 -95.98 -122.21 -95.98 -122.84 -96.335 C -125.2 -97.7 -127.57 -99.07 -129.93 -100.42 C -130.27 -100.57 -130.49 -100.92 -130.46 -101.3 C -130.43 -102.46 -130.45 -103.62 -130.45 -104.78 Z"
15
+ transform="matrix(1, 0, 0, 1, 131.35482788085938, 125.0257797241211)" />
16
+ <path
17
+ class="primary-logo-color"
18
+ d="M -70.504 -100.94 L -70.504 -90.438 C -70.447 -89.98 -70.692 -89.537 -71.11 -89.342 C -78.942 -84.839 -86.769 -80.325 -94.592 -75.8 C -95.635 -75.2 -96.684 -74.612 -97.713 -73.988 C -98.17 -73.708 -98.255 -73.846 -98.255 -74.314 L -98.255 -82.785 C -98.268 -83.116 -98.07 -83.419 -97.762 -83.541 C -92.003 -86.86 -86.269 -90.236 -80.468 -93.47 C -79.181 -94.179 -78.667 -94.934 -78.731 -96.441 C -78.869 -99.76 -78.791 -103.09 -78.755 -106.42 C -78.694 -107 -79.02 -107.56 -79.56 -107.8 C -81.436 -108.83 -83.28 -109.93 -85.138 -110.99 C -85.734 -111.34 -85.734 -111.34 -85.113 -111.7 C -82.748 -113.07 -80.379 -114.43 -78.021 -115.82 C -77.707 -116.05 -77.283 -116.06 -76.957 -115.84 C -74.962 -114.66 -72.953 -113.5 -70.929 -112.37 C -70.62 -112.19 -70.456 -111.84 -70.521 -111.49 C -70.514 -107.99 -70.508 -104.48 -70.504 -100.94 Z"
19
+ transform="matrix(1, 0, 0, 1, 131.35482788085938, 125.0257797241211)" />
20
+ <path
21
+ class="primary-logo-color"
22
+ d="M -108.68 -85.743 L -108.68 -75.169 C -108.72 -74.754 -108.5 -74.358 -108.12 -74.179 C -104.77 -72.267 -101.44 -70.339 -98.117 -68.396 C -97.762 -68.141 -97.284 -68.141 -96.929 -68.396 C -95.028 -69.527 -93.096 -70.598 -91.195 -71.725 C -90.667 -72.041 -90.581 -71.892 -90.581 -71.371 C -90.596 -68.591 -90.596 -65.811 -90.581 -63.03 C -90.551 -62.7 -90.729 -62.386 -91.028 -62.243 C -93.083 -61.073 -95.13 -59.891 -97.17 -58.697 C -97.436 -58.537 -97.775 -58.569 -98.007 -58.775 C -102.74 -61.517 -107.47 -64.254 -112.22 -66.984 C -113.63 -67.796 -115.01 -68.615 -116.42 -69.406 C -116.77 -69.561 -116.97 -69.913 -116.94 -70.286 C -116.93 -80.555 -116.93 -90.823 -116.94 -101.09 C -116.94 -101.63 -116.86 -101.75 -116.35 -101.44 C -113.98 -100.05 -111.59 -98.667 -109.19 -97.303 C -108.84 -97.135 -108.62 -96.76 -108.66 -96.367 C -108.68 -92.833 -108.69 -89.291 -108.68 -85.743 Z"
23
+ transform="matrix(1, 0, 0, 1, 131.35482788085938, 125.0257797241211)" />
24
+ <path
25
+ class="secondary-logo-color"
26
+ d="M -122.18 -85.807 L -122.18 -82.129 C -122.18 -81.637 -122.34 -81.615 -122.72 -81.839 C -125.16 -83.257 -127.6 -84.667 -130.05 -86.069 C -130.35 -86.219 -130.53 -86.535 -130.5 -86.867 L -130.5 -94.09 C -130.5 -94.64 -130.34 -94.679 -129.89 -94.417 C -127.49 -92.998 -125.09 -91.607 -122.67 -90.243 C -122.35 -90.103 -122.15 -89.772 -122.18 -89.42 C -122.21 -88.214 -122.18 -87.012 -122.18 -85.807 Z M -82.688 -119.15 C -83.954 -118.41 -85.17 -117.7 -86.365 -117.02 C -87.748 -116.22 -89.138 -115.44 -90.514 -114.63 C -90.761 -114.45 -91.093 -114.45 -91.34 -114.63 C -93.432 -115.86 -95.535 -117.07 -97.649 -118.27 C -98.053 -118.5 -98.191 -118.63 -97.67 -118.93 C -95.216 -120.32 -92.776 -121.74 -90.337 -123.15 C -90.134 -123.33 -89.845 -123.36 -89.61 -123.23 L -82.918 -119.33 C -82.862 -119.28 -82.812 -119.24 -82.688 -119.15 Z M -85.365 -65.616 L -85.365 -72.062 L -85.365 -74.622 C -85.403 -74.928 -85.24 -75.223 -84.961 -75.353 C -82.886 -76.534 -80.83 -77.736 -78.77 -78.931 C -78.174 -79.286 -78.135 -79.257 -78.135 -78.576 L -78.135 -70.303 C -78.135 -69.991 -78.135 -69.711 -78.468 -69.52 C -80.656 -68.275 -82.833 -67.013 -85.014 -65.761 C -85.127 -65.704 -85.245 -65.655 -85.365 -65.616 Z"
27
+ transform="matrix(1, 0, 0, 1, 131.35482788085938, 125.0257797241211)" />
28
+ </svg>
29
+ `
30
+ })
31
+ export class LogoComponent {
32
+ @Input() width: number;
33
+ @Input() height: number;
34
+ }
@@ -0,0 +1,119 @@
1
+ import { Component, EventEmitter, inject, Input, OnInit, Output } from '@angular/core';
2
+ import { ButtonModule } from 'primeng/button';
3
+ import { DialogModule } from 'primeng/dialog';
4
+ import { InputTextModule } from 'primeng/inputtext';
5
+ import { SelectModule } from 'primeng/select';
6
+ import { FormsModule } from '@angular/forms';
7
+ import { TranslatePipe } from '@ngx-translate/core';
8
+ import { AddModuleInstanceDto, IntKeyValueDto } from '../../api/data-contracts';
9
+ import { Menu } from '../../api/Menu';
10
+ import { MenuService } from '../../services/app.menu.service';
11
+
12
+ @Component({
13
+ selector: 'menu-item-create-dialog',
14
+ standalone: true,
15
+ imports: [ButtonModule, DialogModule, InputTextModule, SelectModule, FormsModule, TranslatePipe],
16
+ template: `
17
+ <p-dialog
18
+ header="{{ 'menuItemCreateDialogComponent.header' | translate }}"
19
+ [modal]="true"
20
+ [style]="{ width: '40rem' }"
21
+ [(visible)]="visible">
22
+ @if (menuService.contextMenuItem) {
23
+ <div class="flex items-center gap-4 mb-4 mt-1">
24
+ <label class="font-semibold w-1/3" for="oip-menu-item-create-dialog-parent-input">
25
+ {{ 'menuItemCreateDialogComponent.parentLabel' | translate }}
26
+ </label>
27
+ <input
28
+ autocomplete="off"
29
+ class="flex-auto"
30
+ id="oip-menu-item-create-dialog-parent-input"
31
+ pInputText
32
+ readonly
33
+ [ngModel]="menuService.contextMenuItem?.label" />
34
+ </div>
35
+ }
36
+ <div class="flex items-center gap-4 mb-4">
37
+ <label class="font-semibold w-1/3" for="oip-menu-item-create-label">
38
+ {{ 'menuItemCreateDialogComponent.label' | translate }}
39
+ </label>
40
+ <input autocomplete="off" class="flex-auto" id="oip-menu-item-create-label" pInputText [(ngModel)]="label" />
41
+ </div>
42
+ <div class="flex items-center gap-4 mb-4">
43
+ <label class="font-semibold w-1/3" for="oip-menu-item-create-module">
44
+ {{ 'menuItemCreateDialogComponent.module' | translate }}
45
+ </label>
46
+ <p-select
47
+ appendTo="body"
48
+ class="flex-auto"
49
+ id="oip-menu-item-create-module"
50
+ optionLabel="value"
51
+ optionValue="key"
52
+ placeholder="{{ 'menuItemCreateDialogComponent.selectModule' | translate }}"
53
+ [options]="modules"
54
+ [(ngModel)]="selectModule" />
55
+ </div>
56
+ <div class="flex items-center gap-4 mb-4">
57
+ <label class="font-semibold w-1/3" for="oip-menu-item-create-dialog-icon">
58
+ {{ 'menuItemCreateDialogComponent.icon' | translate }}
59
+ </label>
60
+ <i class="{{ selectIcon }}"></i>
61
+ <input class="flex-auto" id="oip-menu-item-create-dialog-icon" pInputText [(ngModel)]="selectIcon" />
62
+ </div>
63
+ <div class="flex justify-end gap-2">
64
+ <p-button
65
+ id="oip-menu-item-create-cancel"
66
+ label="{{ 'menuItemCreateDialogComponent.cancel' | translate }}"
67
+ severity="secondary"
68
+ (click)="changeVisible()"
69
+ (keydown)="changeVisible()" />
70
+ <p-button
71
+ id="oip-menu-item-create-save"
72
+ label="{{ 'menuItemCreateDialogComponent.save' | translate }}"
73
+ (click)="save()"
74
+ (keydown)="save()" />
75
+ </div>
76
+ </p-dialog>
77
+ `
78
+ })
79
+ export class MenuItemCreateDialogComponent implements OnInit {
80
+ menuService = inject(MenuService);
81
+ protected readonly menu = inject(Menu);
82
+ @Input() visible!: boolean;
83
+ @Output() visibleChange = new EventEmitter<boolean>();
84
+ modules: IntKeyValueDto[] = [];
85
+ selectModule: any;
86
+ label: string;
87
+ selectIcon: string = 'pi pi-box';
88
+
89
+ async ngOnInit() {
90
+ this.modules = await this.menu.menuGetModules();
91
+ }
92
+
93
+ changeVisible() {
94
+ this.visible = !this.visible;
95
+ this.visibleChange.emit(this.visible);
96
+ }
97
+
98
+ async save() {
99
+ const item: AddModuleInstanceDto = {
100
+ moduleId: this.selectModule,
101
+ label: this.label,
102
+ icon: this.selectIcon,
103
+ parentId: this.menuService.contextMenuItem?.moduleInstanceId
104
+ };
105
+ await this.menuService.addModuleInstance(item);
106
+ await this.menuService.loadMenu();
107
+ this.hide();
108
+ }
109
+
110
+ hide() {
111
+ this.visible = false;
112
+ this.visibleChange.emit(this.visible);
113
+ }
114
+
115
+ showDialog() {
116
+ this.visible = true;
117
+ this.visibleChange.emit(this.visible);
118
+ }
119
+ }