oip-common 0.0.1

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 (127) hide show
  1. package/README.md +25 -0
  2. package/ng-package.json +8 -0
  3. package/package.json +16 -0
  4. package/src/api/FolderModule.ts +124 -0
  5. package/src/api/Menu.ts +134 -0
  6. package/src/api/Module.ts +92 -0
  7. package/src/api/Security.ts +40 -0
  8. package/src/api/Service.ts +57 -0
  9. package/src/api/data-contracts.ts +186 -0
  10. package/src/api/http-client.ts +276 -0
  11. package/src/assets/demo/code.scss +17 -0
  12. package/src/assets/demo/data/products-small.json +124 -0
  13. package/src/assets/demo/demo.scss +2 -0
  14. package/src/assets/demo/flags/flags.scss +740 -0
  15. package/src/assets/demo/flags/flags_responsive.png +0 -0
  16. package/src/assets/demo/images/access/asset-access.svg +46 -0
  17. package/src/assets/demo/images/blocks/hero/hero-1.png +0 -0
  18. package/src/assets/demo/images/blocks/logos/hyper.svg +3 -0
  19. package/src/assets/demo/images/error/asset-error.svg +74 -0
  20. package/src/assets/demo/images/flag/flag_placeholder.png +0 -0
  21. package/src/assets/demo/images/product/bamboo-watch.jpg +0 -0
  22. package/src/assets/demo/images/product/black-watch.jpg +0 -0
  23. package/src/assets/demo/images/product/blue-band.jpg +0 -0
  24. package/src/assets/demo/images/product/blue-t-shirt.jpg +0 -0
  25. package/src/assets/demo/images/product/bracelet.jpg +0 -0
  26. package/src/assets/demo/images/product/brown-purse.jpg +0 -0
  27. package/src/assets/demo/images/product/chakra-bracelet.jpg +0 -0
  28. package/src/assets/demo/images/product/galaxy-earrings.jpg +0 -0
  29. package/src/assets/demo/images/product/game-controller.jpg +0 -0
  30. package/src/assets/demo/images/product/gaming-set.jpg +0 -0
  31. package/src/assets/demo/images/product/gold-phone-case.jpg +0 -0
  32. package/src/assets/demo/images/product/green-earbuds.jpg +0 -0
  33. package/src/assets/demo/images/product/green-t-shirt.jpg +0 -0
  34. package/src/assets/demo/images/product/grey-t-shirt.jpg +0 -0
  35. package/src/assets/demo/images/product/headphones.jpg +0 -0
  36. package/src/assets/demo/images/product/light-green-t-shirt.jpg +0 -0
  37. package/src/assets/demo/images/product/lime-band.jpg +0 -0
  38. package/src/assets/demo/images/product/mini-speakers.jpg +0 -0
  39. package/src/assets/demo/images/product/painted-phone-case.jpg +0 -0
  40. package/src/assets/demo/images/product/pink-band.jpg +0 -0
  41. package/src/assets/demo/images/product/pink-purse.jpg +0 -0
  42. package/src/assets/demo/images/product/product-placeholder.svg +10 -0
  43. package/src/assets/demo/images/product/purple-band.jpg +0 -0
  44. package/src/assets/demo/images/product/purple-gemstone-necklace.jpg +0 -0
  45. package/src/assets/demo/images/product/purple-t-shirt.jpg +0 -0
  46. package/src/assets/demo/images/product/shoes.jpg +0 -0
  47. package/src/assets/demo/images/product/sneakers.jpg +0 -0
  48. package/src/assets/demo/images/product/teal-t-shirt.jpg +0 -0
  49. package/src/assets/demo/images/product/yellow-earbuds.jpg +0 -0
  50. package/src/assets/demo/images/product/yoga-mat.jpg +0 -0
  51. package/src/assets/demo/images/product/yoga-set.jpg +0 -0
  52. package/src/assets/favicon.svg +14 -0
  53. package/src/assets/i18n/app-modules.en.json +23 -0
  54. package/src/assets/i18n/app-modules.ru.json +23 -0
  55. package/src/assets/i18n/config.en.json +14 -0
  56. package/src/assets/i18n/config.ru.json +14 -0
  57. package/src/assets/layout/_core.scss +24 -0
  58. package/src/assets/layout/_footer.scss +8 -0
  59. package/src/assets/layout/_logo.scss +7 -0
  60. package/src/assets/layout/_main.scss +12 -0
  61. package/src/assets/layout/_menu.scss +159 -0
  62. package/src/assets/layout/_mixins.scss +15 -0
  63. package/src/assets/layout/_preloading.scss +49 -0
  64. package/src/assets/layout/_responsive.scss +108 -0
  65. package/src/assets/layout/_topbar.scss +168 -0
  66. package/src/assets/layout/_typography.scss +68 -0
  67. package/src/assets/layout/_utils.scss +25 -0
  68. package/src/assets/layout/layout.scss +14 -0
  69. package/src/assets/layout/variables/_common.scss +20 -0
  70. package/src/assets/layout/variables/_dark.scss +5 -0
  71. package/src/assets/layout/variables/_light.scss +5 -0
  72. package/src/assets/oip-common.scss +5 -0
  73. package/src/assets/tailwind.css +3 -0
  74. package/src/components/app-configurator.component.ts +491 -0
  75. package/src/components/app-floating-configurator.component.ts +47 -0
  76. package/src/components/app-modules.component.ts +144 -0
  77. package/src/components/app.layout.component.ts +130 -0
  78. package/src/components/auth/access/access.component.ts +42 -0
  79. package/src/components/auth/error/error.component.ts +42 -0
  80. package/src/components/auth/login/login.component.ts +120 -0
  81. package/src/components/auth/unauthorized/unauthorized.component.ts +51 -0
  82. package/src/components/base-module.component.ts +258 -0
  83. package/src/components/config.component.ts +131 -0
  84. package/src/components/db-migration/db-migration.component.ts +162 -0
  85. package/src/components/db-migration.component.ts +154 -0
  86. package/src/components/footer.component.ts +17 -0
  87. package/src/components/logo.component.ts +34 -0
  88. package/src/components/menu/menu-item-create-dialog.component.ts +119 -0
  89. package/src/components/menu/menu-item-edit-dialog.component.ts +123 -0
  90. package/src/components/menu/menu-item.component.ts +295 -0
  91. package/src/components/menu/menu.component.ts +85 -0
  92. package/src/components/notfound.component.ts +31 -0
  93. package/src/components/profile.component.ts +43 -0
  94. package/src/components/security.component.ts +102 -0
  95. package/src/components/sidebar.component.ts +12 -0
  96. package/src/components/top-bar.component.ts +147 -0
  97. package/src/dtos/context-menu-item.dto.ts +23 -0
  98. package/src/dtos/edit-module-instance.dto.ts +8 -0
  99. package/src/dtos/no-settings.dto.ts +4 -0
  100. package/src/dtos/put-security.dto.ts +6 -0
  101. package/src/dtos/security.dto.ts +6 -0
  102. package/src/dtos/top-bar.dto.ts +13 -0
  103. package/src/events/menu-change.event.ts +23 -0
  104. package/src/helpers/date.helper.ts +94 -0
  105. package/src/intercepts/i18n-intercept.service.ts +13 -0
  106. package/src/modules/http-loader.factory.ts +40 -0
  107. package/src/modules/secure.pipe.ts +19 -0
  108. package/src/public-api.ts +42 -0
  109. package/src/services/app-title.service.ts +22 -0
  110. package/src/services/app.layout.service.ts +236 -0
  111. package/src/services/app.menu.service.ts +64 -0
  112. package/src/services/auth.service.ts +58 -0
  113. package/src/services/base-data.service.ts +74 -0
  114. package/src/services/l10n.service.ts +71 -0
  115. package/src/services/msg.service.ts +76 -0
  116. package/src/services/security-data.service.ts +19 -0
  117. package/src/services/security-storage.service.ts +21 -0
  118. package/src/services/security.service.ts +116 -0
  119. package/src/services/top-bar.service.ts +44 -0
  120. package/src/services/user.service.ts +77 -0
  121. package/src/test.ts +11 -0
  122. package/src/user-api/UserProfile.ts +85 -0
  123. package/src/user-api/data-contracts.ts +42 -0
  124. package/src/user-api/http-client.ts +251 -0
  125. package/tsconfig.lib.json +12 -0
  126. package/tsconfig.lib.prod.json +10 -0
  127. package/tsconfig.spec.json +9 -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,162 @@
1
+ import { Component, inject, OnDestroy, OnInit } from '@angular/core';
2
+ import { BaseModuleComponent, NoSettingsDto, SecurityComponent } from 'oip-common';
3
+ import { TagModule } from 'primeng/tag';
4
+ import { ConfirmationService, SharedModule } from 'primeng/api';
5
+ import { TableModule } from 'primeng/table';
6
+ import { InputTextModule } from 'primeng/inputtext';
7
+ import { TextareaModule } from 'primeng/textarea';
8
+ import { ButtonModule } from 'primeng/button';
9
+ import { FormsModule } from '@angular/forms';
10
+ import { ConfirmDialog } from 'primeng/confirmdialog';
11
+ import { NgIf } from '@angular/common';
12
+ import { Tooltip } from 'primeng/tooltip';
13
+ import { ActivatedRoute } from '@angular/router';
14
+
15
+ export interface MigrationDto {
16
+ name: string;
17
+ applied: boolean;
18
+ pending: boolean;
19
+ exist: boolean;
20
+ }
21
+
22
+ export interface ApplyMigrationRequest {
23
+ name: string;
24
+ }
25
+
26
+ @Component({
27
+ imports: [
28
+ TableModule,
29
+ SharedModule,
30
+ TagModule,
31
+ InputTextModule,
32
+ TextareaModule,
33
+ ButtonModule,
34
+ FormsModule,
35
+ ConfirmDialog,
36
+ NgIf,
37
+ SecurityComponent,
38
+ Tooltip
39
+ ],
40
+ selector: 'crypt',
41
+ template: `
42
+ <div *ngIf="isContent" class="card" style="height: 100%">
43
+ <p-confirmDialog />
44
+ <div>
45
+ <h5>Migration manager</h5>
46
+ <div class="flex flex-row gap-2">
47
+ <p-button
48
+ icon="pi pi-refresh"
49
+ pTooltip="Refresh"
50
+ severity="secondary"
51
+ tooltipPosition="bottom"
52
+ [outlined]="true"
53
+ (click)="refreshAction()" />
54
+ <p-button
55
+ icon="pi pi-filter-slash"
56
+ pTooltip="Clean filter"
57
+ severity="secondary"
58
+ tooltipPosition="bottom"
59
+ [outlined]="true"
60
+ (click)="dt.clear()" />
61
+ </div>
62
+ <div>
63
+ <p-table #dt dataKey="name" editMode="row" size="small" [scrollable]="true" [value]="data">
64
+ <ng-template let-columns pTemplate="header">
65
+ <tr>
66
+ <th pSortableColumn="name" scope="col">
67
+ Migration name
68
+ <p-columnFilter display="menu" field="name" type="text" />
69
+ </th>
70
+ <th scope="col">Applied</th>
71
+ <th scope="col">Exist</th>
72
+ <th>Pending</th>
73
+ <th scope="col"></th>
74
+ </tr>
75
+ </ng-template>
76
+
77
+ <ng-template #body let-columns="columns" let-editing="editing" let-ri="rowIndex" let-rowData>
78
+ <tr [pEditableRow]="rowData">
79
+ <td>
80
+ {{ rowData.name }}
81
+ </td>
82
+ <td>
83
+ <p-button
84
+ *ngIf="rowData.applied"
85
+ icon="pi pi-check"
86
+ severity="success"
87
+ [rounded]="true"
88
+ [text]="true">
89
+ </p-button>
90
+ </td>
91
+ <td>
92
+ <p-button *ngIf="rowData.exist" icon="pi pi-check" severity="success" [rounded]="true" [text]="true">
93
+ </p-button>
94
+ </td>
95
+ <td>
96
+ <p-button
97
+ *ngIf="rowData.pending"
98
+ icon="pi pi-check"
99
+ severity="success"
100
+ [rounded]="true"
101
+ [text]="true">
102
+ </p-button>
103
+ </td>
104
+ <td>
105
+ <p-button
106
+ icon="pi pi-bolt"
107
+ pCancelEditableRow
108
+ pTooltip="Apply migration"
109
+ severity="secondary"
110
+ tooltipPosition="left"
111
+ [rounded]="true"
112
+ [text]="true"
113
+ (click)="applyMigration(rowData)">
114
+ </p-button>
115
+ </td>
116
+ </tr>
117
+ </ng-template>
118
+ </p-table>
119
+ </div>
120
+ </div>
121
+ </div>
122
+ <security *ngIf="isSecurity" [controller]="controller" [id]="id"></security>
123
+ `,
124
+ providers: [ConfirmationService]
125
+ })
126
+ export class DbMigrationComponent
127
+ extends BaseModuleComponent<NoSettingsDto, NoSettingsDto>
128
+ implements OnInit, OnDestroy
129
+ {
130
+ private readonly activatedRoute = inject(ActivatedRoute);
131
+ controller: string = '';
132
+ data: MigrationDto[];
133
+
134
+ async ngOnInit() {
135
+ this.activatedRoute.url.subscribe((url) => {
136
+ this.controller = url[0].toString();
137
+ });
138
+ this.appTitleService.setTitle('Db Migration');
139
+ await super.ngOnInit();
140
+ await this.refreshAction();
141
+ }
142
+
143
+ async refreshAction() {
144
+ this.getData()
145
+ .then((response) => {
146
+ this.data = response;
147
+ })
148
+ .catch((error) => {
149
+ console.log(error);
150
+ this.msgService.error('Error refreshing database');
151
+ });
152
+ }
153
+
154
+ async getData() {
155
+ return this.baseDataService.sendRequest<MigrationDto[]>(`api/${this.controller}/get-migrations`, 'GET');
156
+ }
157
+
158
+ async applyMigration(rowData: MigrationDto) {
159
+ const request = { name: rowData.name } as ApplyMigrationRequest;
160
+ return this.baseDataService.sendRequest(`api/${this.controller}/apply-migration`, 'POST', request);
161
+ }
162
+ }
@@ -0,0 +1,154 @@
1
+ import { Component, OnDestroy, OnInit } from '@angular/core';
2
+ import { BaseModuleComponent, NoSettingsDto, SecurityComponent } from 'oip-common';
3
+ import { TagModule } from 'primeng/tag';
4
+ import { ConfirmationService, SharedModule } from 'primeng/api';
5
+ import { TableModule } from 'primeng/table';
6
+ import { InputTextModule } from 'primeng/inputtext';
7
+ import { TextareaModule } from 'primeng/textarea';
8
+ import { ButtonModule } from 'primeng/button';
9
+ import { FormsModule } from '@angular/forms';
10
+ import { ConfirmDialog } from 'primeng/confirmdialog';
11
+ import { NgIf } from '@angular/common';
12
+ import { Tooltip } from 'primeng/tooltip';
13
+
14
+ export interface MigrationDto {
15
+ name: string;
16
+ applied: boolean;
17
+ pending: boolean;
18
+ exist: boolean;
19
+ }
20
+
21
+ export interface ApplyMigrationRequest {
22
+ name: string;
23
+ }
24
+
25
+ @Component({
26
+ imports: [
27
+ TableModule,
28
+ SharedModule,
29
+ TagModule,
30
+ InputTextModule,
31
+ TextareaModule,
32
+ ButtonModule,
33
+ FormsModule,
34
+ ConfirmDialog,
35
+ NgIf,
36
+ SecurityComponent,
37
+ Tooltip
38
+ ],
39
+ selector: 'db-migration',
40
+ template: `
41
+ <div *ngIf="isContent" class="card" style="height: 100%">
42
+ <p-confirmDialog />
43
+ <div>
44
+ <h5>Migration manager</h5>
45
+ <div class="flex flex-row gap-2">
46
+ <p-button
47
+ icon="pi pi-refresh"
48
+ pTooltip="Refresh"
49
+ severity="secondary"
50
+ tooltipPosition="bottom"
51
+ [outlined]="true"
52
+ (click)="refreshAction()" />
53
+ <p-button
54
+ icon="pi pi-filter-slash"
55
+ pTooltip="Clean filter"
56
+ severity="secondary"
57
+ tooltipPosition="bottom"
58
+ [outlined]="true"
59
+ (click)="dt.clear()" />
60
+ </div>
61
+ <div>
62
+ <p-table #dt dataKey="name" editMode="row" size="small" [scrollable]="true" [value]="data">
63
+ <ng-template let-columns pTemplate="header">
64
+ <tr>
65
+ <th pSortableColumn="name" scope="col">
66
+ Migration name
67
+ <p-columnFilter display="menu" field="name" type="text" />
68
+ </th>
69
+ <th scope="col">Applied</th>
70
+ <th scope="col">Exist</th>
71
+ <th>Pending</th>
72
+ <th scope="col"></th>
73
+ </tr>
74
+ </ng-template>
75
+
76
+ <ng-template #body let-columns="columns" let-editing="editing" let-ri="rowIndex" let-rowData>
77
+ <tr [pEditableRow]="rowData">
78
+ <td>
79
+ {{ rowData.name }}
80
+ </td>
81
+ <td>
82
+ <p-button
83
+ *ngIf="rowData.applied"
84
+ icon="pi pi-check"
85
+ severity="success"
86
+ [rounded]="true"
87
+ [text]="true">
88
+ </p-button>
89
+ </td>
90
+ <td>
91
+ @if (rowData.exist) {
92
+ <p-button icon="pi pi-check" severity="success" [rounded]="true" [text]="true" />
93
+ }
94
+ </td>
95
+ <td>
96
+ @if (rowData.pending) {
97
+ <p-button icon="pi pi-check" severity="success" [rounded]="true" [text]="true"></p-button>
98
+ }
99
+ </td>
100
+ <td>
101
+ <p-button
102
+ icon="pi pi-bolt"
103
+ pCancelEditableRow
104
+ pTooltip="Apply migration"
105
+ severity="secondary"
106
+ tooltipPosition="left"
107
+ [rounded]="true"
108
+ [text]="true"
109
+ (click)="applyMigration(rowData)">
110
+ </p-button>
111
+ </td>
112
+ </tr>
113
+ </ng-template>
114
+ </p-table>
115
+ </div>
116
+ </div>
117
+ </div>
118
+ @if (isSecurity) {
119
+ <security [controller]="controller" [id]="id" />
120
+ }
121
+ `,
122
+ providers: [ConfirmationService]
123
+ })
124
+ export class DbMigrationComponent
125
+ extends BaseModuleComponent<NoSettingsDto, NoSettingsDto>
126
+ implements OnInit, OnDestroy
127
+ {
128
+ data: MigrationDto[];
129
+
130
+ async ngOnInit() {
131
+ await super.ngOnInit();
132
+ await this.refreshAction();
133
+ }
134
+
135
+ async refreshAction() {
136
+ this.getData()
137
+ .then((response) => {
138
+ this.data = response;
139
+ })
140
+ .catch((error) => {
141
+ console.log(error);
142
+ this.msgService.error('Error refreshing database');
143
+ });
144
+ }
145
+
146
+ async getData() {
147
+ return this.baseDataService.sendRequest<MigrationDto[]>(`api/${this.controller}/get-migrations`, 'GET');
148
+ }
149
+
150
+ async applyMigration(rowData: MigrationDto) {
151
+ const request = { name: rowData.name } as ApplyMigrationRequest;
152
+ return this.baseDataService.sendRequest(`api/${this.controller}/apply-migration`, 'POST', request);
153
+ }
154
+ }
@@ -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 { MenuService } from 'oip-common';
8
+ import { TranslatePipe } from '@ngx-translate/core';
9
+ import { AddModuleInstanceDto, IntKeyValueDto } from '../../api/data-contracts';
10
+ import { Menu } from '../../api/Menu';
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
+ }