oip-common 0.1.8 → 0.2.0

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.
@@ -0,0 +1,10 @@
1
+ {
2
+ "iframe-module": {
3
+ "iframeModule": {
4
+ "urlPlaceholder": "Site URL",
5
+ "settingSaveButtonLabel": "Save",
6
+ "emptyUrlMessage": "Site URL is not specified.",
7
+ "siteLoadingMessage": "Failed to load the site."
8
+ }
9
+ }
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "iframe-module": {
3
+ "iframeModule": {
4
+ "urlPlaceholder": "URL сайта",
5
+ "settingSaveButtonLabel": "Сохранить",
6
+ "emptyUrlMessage": "URL сайта не указан.",
7
+ "siteLoadingMessage": "Не удалось загрузить сайт."
8
+ }
9
+ }
10
+ }
@@ -39,7 +39,7 @@ import { ContextMenuModule, ContextMenu } from 'primeng/contextmenu';
39
39
  import * as i2$3 from 'primeng/dialog';
40
40
  import { DialogModule } from 'primeng/dialog';
41
41
  import * as i3$3 from 'primeng/inputtext';
42
- import { InputTextModule } from 'primeng/inputtext';
42
+ import { InputTextModule, InputText } from 'primeng/inputtext';
43
43
  import { trigger, state, transition, style, animate } from '@angular/animations';
44
44
  import * as i3$2 from 'primeng/ripple';
45
45
  import { RippleModule } from 'primeng/ripple';
@@ -1177,76 +1177,76 @@ class SecurityComponent {
1177
1177
  }
1178
1178
  }
1179
1179
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SecurityComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1180
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: SecurityComponent, isStandalone: true, selector: "security", inputs: { id: "id", controller: "controller" }, usesOnChanges: true, ngImport: i0, template: `
1181
- <div class="flex flex-col md:flex-row gap-8">
1182
- <div class="md:w-1/2">
1183
- <div class="card flex flex-col gap-4">
1184
- <div class="font-semibold text-xl">
1185
- {{ 'securityComponent.security' | translate }}
1186
- </div>
1187
- @for (item of securityData; track item.name) {
1188
- <div class="flex flex-col gap-2">
1189
- <label htmlFor="oip-security-multiselect-{{ item.name }}">
1190
- {{ item.name }}
1191
- <span class="pi pi-question-circle" pTooltip="{{ item.description }}" tooltipPosition="right"></span>
1192
- </label>
1193
- <p-multiSelect
1194
- id="oip-security-multiselect-{{ item.name }}"
1195
- placeholder="{{ 'securityComponent.selectRoles' | translate }}"
1196
- [maxSelectedLabels]="10"
1197
- [options]="roles"
1198
- [(ngModel)]="item.roles" />
1199
- </div>
1200
- }
1201
- <div class="flex justify-content-end flex-wrap">
1202
- <p-button
1203
- icon="pi pi-save"
1204
- id="oip-security-save-button"
1205
- label="{{ 'securityComponent.save' | translate }}"
1206
- (click)="saveClick()"
1207
- (keydown)="saveKeyDown($event)" />
1208
- </div>
1209
- </div>
1210
- </div>
1211
- </div>
1180
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: SecurityComponent, isStandalone: true, selector: "security", inputs: { id: "id", controller: "controller" }, usesOnChanges: true, ngImport: i0, template: `
1181
+ <div class="flex flex-col md:flex-row gap-8">
1182
+ <div class="md:w-1/2">
1183
+ <div class="card flex flex-col gap-4">
1184
+ <div class="font-semibold text-xl">
1185
+ {{ 'securityComponent.security' | translate }}
1186
+ </div>
1187
+ @for (item of securityData; track item.name) {
1188
+ <div class="flex flex-col gap-2">
1189
+ <label htmlFor="oip-security-multiselect-{{ item.name }}">
1190
+ {{ item.name }}
1191
+ <span class="pi pi-question-circle" pTooltip="{{ item.description }}" tooltipPosition="right"></span>
1192
+ </label>
1193
+ <p-multiSelect
1194
+ id="oip-security-multiselect-{{ item.name }}"
1195
+ placeholder="{{ 'securityComponent.selectRoles' | translate }}"
1196
+ [maxSelectedLabels]="10"
1197
+ [options]="roles"
1198
+ [(ngModel)]="item.roles" />
1199
+ </div>
1200
+ }
1201
+ <div class="flex justify-content-end flex-wrap">
1202
+ <p-button
1203
+ icon="pi pi-save"
1204
+ id="oip-security-save-button"
1205
+ label="{{ 'securityComponent.save' | translate }}"
1206
+ (click)="saveClick()"
1207
+ (keydown)="saveKeyDown($event)" />
1208
+ </div>
1209
+ </div>
1210
+ </div>
1211
+ </div>
1212
1212
  `, isInline: true, dependencies: [{ kind: "ngmodule", type: MultiSelectModule }, { kind: "component", type: i1.MultiSelect, selector: "p-multiSelect, p-multiselect, p-multi-select", inputs: ["id", "ariaLabel", "styleClass", "panelStyle", "panelStyleClass", "inputId", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "dataKey", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "chipIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "showClear", "autofocus", "placeholder", "options", "filterValue", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus", "highlightOnSelect", "size", "variant", "fluid", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i2.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
1213
1213
  }
1214
1214
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SecurityComponent, decorators: [{
1215
1215
  type: Component,
1216
1216
  args: [{
1217
1217
  selector: 'security',
1218
- template: `
1219
- <div class="flex flex-col md:flex-row gap-8">
1220
- <div class="md:w-1/2">
1221
- <div class="card flex flex-col gap-4">
1222
- <div class="font-semibold text-xl">
1223
- {{ 'securityComponent.security' | translate }}
1224
- </div>
1225
- @for (item of securityData; track item.name) {
1226
- <div class="flex flex-col gap-2">
1227
- <label htmlFor="oip-security-multiselect-{{ item.name }}">
1228
- {{ item.name }}
1229
- <span class="pi pi-question-circle" pTooltip="{{ item.description }}" tooltipPosition="right"></span>
1230
- </label>
1231
- <p-multiSelect
1232
- id="oip-security-multiselect-{{ item.name }}"
1233
- placeholder="{{ 'securityComponent.selectRoles' | translate }}"
1234
- [maxSelectedLabels]="10"
1235
- [options]="roles"
1236
- [(ngModel)]="item.roles" />
1237
- </div>
1238
- }
1239
- <div class="flex justify-content-end flex-wrap">
1240
- <p-button
1241
- icon="pi pi-save"
1242
- id="oip-security-save-button"
1243
- label="{{ 'securityComponent.save' | translate }}"
1244
- (click)="saveClick()"
1245
- (keydown)="saveKeyDown($event)" />
1246
- </div>
1247
- </div>
1248
- </div>
1249
- </div>
1218
+ template: `
1219
+ <div class="flex flex-col md:flex-row gap-8">
1220
+ <div class="md:w-1/2">
1221
+ <div class="card flex flex-col gap-4">
1222
+ <div class="font-semibold text-xl">
1223
+ {{ 'securityComponent.security' | translate }}
1224
+ </div>
1225
+ @for (item of securityData; track item.name) {
1226
+ <div class="flex flex-col gap-2">
1227
+ <label htmlFor="oip-security-multiselect-{{ item.name }}">
1228
+ {{ item.name }}
1229
+ <span class="pi pi-question-circle" pTooltip="{{ item.description }}" tooltipPosition="right"></span>
1230
+ </label>
1231
+ <p-multiSelect
1232
+ id="oip-security-multiselect-{{ item.name }}"
1233
+ placeholder="{{ 'securityComponent.selectRoles' | translate }}"
1234
+ [maxSelectedLabels]="10"
1235
+ [options]="roles"
1236
+ [(ngModel)]="item.roles" />
1237
+ </div>
1238
+ }
1239
+ <div class="flex justify-content-end flex-wrap">
1240
+ <p-button
1241
+ icon="pi pi-save"
1242
+ id="oip-security-save-button"
1243
+ label="{{ 'securityComponent.save' | translate }}"
1244
+ (click)="saveClick()"
1245
+ (keydown)="saveKeyDown($event)" />
1246
+ </div>
1247
+ </div>
1248
+ </div>
1249
+ </div>
1250
1250
  `,
1251
1251
  imports: [MultiSelectModule, TooltipModule, FormsModule, ButtonModule, TranslatePipe],
1252
1252
  standalone: true
@@ -6081,6 +6081,152 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
6081
6081
  args: [{ required: true }]
6082
6082
  }] } });
6083
6083
 
6084
+ class IframeModuleComponent extends BaseModuleComponent {
6085
+ constructor() {
6086
+ super();
6087
+ this.renderer = inject(Renderer2);
6088
+ this.translate = inject(TranslateService);
6089
+ this.iframeUrl = null;
6090
+ this.l10nService.loadComponentTranslations('iframe-module');
6091
+ }
6092
+ set iframeElement(element) {
6093
+ this.iframe = element;
6094
+ this.updateIframeSrc();
6095
+ }
6096
+ setIframeUrl(url) {
6097
+ const iframeUrl = url?.trim();
6098
+ if (!iframeUrl) {
6099
+ this.iframeUrl = null;
6100
+ this.updateIframeSrc();
6101
+ const message = this.translate.instant('iframe-module.iframeModule.emptyUrlMessage');
6102
+ this.msgService.warn(message);
6103
+ return;
6104
+ }
6105
+ if (!this.isAllowedIframeUrl(iframeUrl)) {
6106
+ this.iframeUrl = null;
6107
+ this.updateIframeSrc();
6108
+ const message = this.translate.instant('iframe-module.iframeModule.siteLoadingMessage');
6109
+ this.msgService.error(message);
6110
+ return;
6111
+ }
6112
+ this.iframeUrl = iframeUrl;
6113
+ this.updateIframeSrc();
6114
+ }
6115
+ isAllowedIframeUrl(url) {
6116
+ try {
6117
+ const parsedUrl = new URL(url, window.location.origin);
6118
+ return parsedUrl.protocol === 'http:' || parsedUrl.protocol === 'https:';
6119
+ }
6120
+ catch {
6121
+ return false;
6122
+ }
6123
+ }
6124
+ async onModuleInstanceChange() {
6125
+ this.setIframeUrl(this.settings.url);
6126
+ }
6127
+ updateIframeSrc() {
6128
+ if (!this.iframe) {
6129
+ return;
6130
+ }
6131
+ if (!this.iframeUrl) {
6132
+ this.renderer.removeAttribute(this.iframe.nativeElement, 'src');
6133
+ return;
6134
+ }
6135
+ this.renderer.setAttribute(this.iframe.nativeElement, 'src', this.iframeUrl);
6136
+ }
6137
+ onIframeError() {
6138
+ const errorMessage = this.translate.instant('iframe-module.iframeModule.siteLoadingMessage');
6139
+ this.msgService.error(errorMessage);
6140
+ }
6141
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: IframeModuleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6142
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: IframeModuleComponent, isStandalone: true, selector: "ng-component", viewQueries: [{ propertyName: "iframeElement", first: true, predicate: ["iframe"], descendants: true }], usesInheritance: true, ngImport: i0, template: `
6143
+ @if (isContent) {
6144
+ <iframe
6145
+ #iframe
6146
+ class="w-full h-screen"
6147
+ style="background-color: var(--surface-ground)"
6148
+ title="Main iframe"
6149
+ (error)="onIframeError()">
6150
+ </iframe>
6151
+ } @else if (isSettings) {
6152
+ <div class="flex flex-col md:flex-row gap-8">
6153
+ <div class="md:w-1/2">
6154
+ <div class="card flex flex-col gap-4">
6155
+ <div class="font-semibold text-xl">{{ 'baseComponent.settings' | translate }}</div>
6156
+ <div class="col-span-30 md:col-span-10 w-full">
6157
+ <input
6158
+ class="w-full"
6159
+ pInputText
6160
+ placeholder="{{ 'iframe-module.iframeModule.urlPlaceholder' | translate }}"
6161
+ qa-id="iframe-module-settings-site-url-input"
6162
+ type="text"
6163
+ [(ngModel)]="settings.url"/>
6164
+ </div>
6165
+ <div class="flex justify-end">
6166
+ <p-button
6167
+ icon="pi pi-save"
6168
+ label="{{ 'iframe-module.iframeModule.settingSaveButtonLabel' | translate }}"
6169
+ qa-id="iframe-module-settings-save-button"
6170
+ (onClick)="saveSettings(settings)">
6171
+ </p-button>
6172
+ </div>
6173
+ </div>
6174
+ </div>
6175
+ </div>
6176
+ } @else if (isSecurity) {
6177
+ <security [controller]="controller" [id]="id"/>
6178
+ }
6179
+ `, isInline: true, dependencies: [{ kind: "component", type: SecurityComponent, selector: "security", inputs: ["id", "controller"] }, { kind: "directive", type: InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
6180
+ }
6181
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: IframeModuleComponent, decorators: [{
6182
+ type: Component,
6183
+ args: [{
6184
+ standalone: true,
6185
+ imports: [SecurityComponent, TranslatePipe, InputText, FormsModule, Button],
6186
+ template: `
6187
+ @if (isContent) {
6188
+ <iframe
6189
+ #iframe
6190
+ class="w-full h-screen"
6191
+ style="background-color: var(--surface-ground)"
6192
+ title="Main iframe"
6193
+ (error)="onIframeError()">
6194
+ </iframe>
6195
+ } @else if (isSettings) {
6196
+ <div class="flex flex-col md:flex-row gap-8">
6197
+ <div class="md:w-1/2">
6198
+ <div class="card flex flex-col gap-4">
6199
+ <div class="font-semibold text-xl">{{ 'baseComponent.settings' | translate }}</div>
6200
+ <div class="col-span-30 md:col-span-10 w-full">
6201
+ <input
6202
+ class="w-full"
6203
+ pInputText
6204
+ placeholder="{{ 'iframe-module.iframeModule.urlPlaceholder' | translate }}"
6205
+ qa-id="iframe-module-settings-site-url-input"
6206
+ type="text"
6207
+ [(ngModel)]="settings.url"/>
6208
+ </div>
6209
+ <div class="flex justify-end">
6210
+ <p-button
6211
+ icon="pi pi-save"
6212
+ label="{{ 'iframe-module.iframeModule.settingSaveButtonLabel' | translate }}"
6213
+ qa-id="iframe-module-settings-save-button"
6214
+ (onClick)="saveSettings(settings)">
6215
+ </p-button>
6216
+ </div>
6217
+ </div>
6218
+ </div>
6219
+ </div>
6220
+ } @else if (isSecurity) {
6221
+ <security [controller]="controller" [id]="id"/>
6222
+ }
6223
+ `
6224
+ }]
6225
+ }], ctorParameters: () => [], propDecorators: { iframeElement: [{
6226
+ type: ViewChild,
6227
+ args: ['iframe']
6228
+ }] } });
6229
+
6084
6230
  /**
6085
6231
  * A route guard that ensures the user is authenticated and has a valid access token.
6086
6232
  * If the access token is expired, it attempts to refresh the session.
@@ -6309,6 +6455,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
6309
6455
  }]
6310
6456
  }] });
6311
6457
 
6458
+ const appendCurrentOriginSecureRoute = (secureRoutes) => {
6459
+ const currentOriginRoute = `${window.location.origin}/`;
6460
+ return Array.from(new Set([...(secureRoutes ?? []), currentOriginRoute]));
6461
+ };
6312
6462
  /**
6313
6463
  * Load keycloak settings from backend and save to sessionStorage
6314
6464
  * @param httpClient
@@ -6335,7 +6485,7 @@ const httpLoaderAuthFactory = (httpClient) => {
6335
6485
  useRefreshToken: config.useRefreshToken,
6336
6486
  silentRenew: config.silentRenew,
6337
6487
  logLevel: config.logLevel,
6338
- secureRoutes: config.secureRoutes
6488
+ secureRoutes: appendCurrentOriginSecureRoute(config.secureRoutes)
6339
6489
  };
6340
6490
  sessionStorage.setItem(KEYCLOAK_SETTINGS_KEY, JSON.stringify(authConfig));
6341
6491
  return authConfig;
@@ -6350,5 +6500,5 @@ const httpLoaderAuthFactory = (httpClient) => {
6350
6500
  * Generated bundle index. Do not edit.
6351
6501
  */
6352
6502
 
6353
- export { APP_THEME_PRESETS, APP_THEME_PRESETS_MERGE_MODE, AppConfiguratorComponent, AppFloatingConfiguratorComponent, AppLayoutComponent, AppModulesComponent, AppTopbar, AuthGuardService, BaseDataService, BaseModuleComponent, ConfigComponent, ContentType, DEFAULT_OIP_FRONTEND_CONFIG, DbMigrationComponent, DiscussionComponent, ErrorComponent, FooterComponent, HttpClient, KeycloakSecurityService, L10nService, LOGO_COMPONENT_TOKEN, LayoutService, LogoComponent, LogoService, MenuComponent, MenuService, MsgService, NotfoundComponent, NotificationService, OIP_FRONTEND_CONFIG, ProfileComponent, SecurePipe, SecurityComponent, SecurityDataService, SecurityService, SecurityStorageService, SidebarComponent, TableFilterService, TopBarService, UnauthorizedComponent, UserService, httpLoaderAuthFactory, langIntercept, mergeWithDefaults, provideAppThemes, provideLogoComponent, replaceDefaults };
6503
+ export { APP_THEME_PRESETS, APP_THEME_PRESETS_MERGE_MODE, AppConfiguratorComponent, AppFloatingConfiguratorComponent, AppLayoutComponent, AppModulesComponent, AppTopbar, AuthGuardService, BaseDataService, BaseModuleComponent, ConfigComponent, ContentType, DEFAULT_OIP_FRONTEND_CONFIG, DbMigrationComponent, DiscussionComponent, ErrorComponent, FooterComponent, HttpClient, IframeModuleComponent, KeycloakSecurityService, L10nService, LOGO_COMPONENT_TOKEN, LayoutService, LogoComponent, LogoService, MenuComponent, MenuService, MsgService, NotfoundComponent, NotificationService, OIP_FRONTEND_CONFIG, ProfileComponent, SecurePipe, SecurityComponent, SecurityDataService, SecurityService, SecurityStorageService, SidebarComponent, TableFilterService, TopBarService, UnauthorizedComponent, UserService, httpLoaderAuthFactory, langIntercept, mergeWithDefaults, provideAppThemes, provideLogoComponent, replaceDefaults };
6354
6504
  //# sourceMappingURL=oip-common.mjs.map