@nakedobjects/gemini
Version:
Single Page Application client for a Naked Objects application.
904 lines (892 loc) • 384 kB
JavaScript
import * as i0 from '@angular/core';
import { EventEmitter, HostListener, Output, Directive, ViewChildren, Input, Component, ElementRef, ViewChild, Injectable, ViewContainerRef, NgModule } from '@angular/core';
import forEach from 'lodash-es/forEach';
import map from 'lodash-es/map';
import mapValues from 'lodash-es/mapValues';
import zipObject from 'lodash-es/zipObject';
import * as i1 from '@angular/common';
import difference from 'lodash-es/difference';
import findIndex from 'lodash-es/findIndex';
import first from 'lodash-es/first';
import some from 'lodash-es/some';
import flatten from 'lodash-es/flatten';
import * as i3 from '@nakedobjects/view-models';
import { MenuViewModel, DomainObjectViewModel, ListViewModel, CollectionViewModel, ChoiceViewModel, validateDate, PropertyViewModel, RecentItemViewModel, copy, ParameterViewModel, SortType } from '@nakedobjects/view-models';
import * as Ro from '@nakedobjects/restful-objects';
import * as i1$1 from '@angular/router';
import { RouterModule } from '@angular/router';
import * as i2 from '@nakedobjects/services';
import { fixedDateFormat, supportedDateFormats, defaultTimeFormat, defaultShortTimeFormat, shortTimeFormat, CollectionViewState, InteractionMode, ErrorCategory, ClientErrorCode, HttpStatusCode, TypeResultCache, ViewType, Pane } from '@nakedobjects/services';
import * as i4$1 from '@angular/cdk/drag-drop';
import { DragDropModule } from '@angular/cdk/drag-drop';
import find from 'lodash-es/find';
import * as i4 from '@angular/forms';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import every from 'lodash-es/every';
import keys from 'lodash-es/keys';
import omit from 'lodash-es/omit';
import { BehaviorSubject } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
import concat from 'lodash-es/concat';
import { DateTime } from 'luxon';
import filter from 'lodash-es/filter';
import fromPairs from 'lodash-es/fromPairs';
import each from 'lodash-es/each';
import * as i2$1 from '@angular/common/http';
import { HttpClientModule } from '@angular/common/http';
import { BrowserModule } from '@angular/platform-browser';
function safeUnsubscribe(sub) {
if (sub) {
sub.unsubscribe();
}
}
function isFocusable(nativeElement) {
return !!(nativeElement && nativeElement instanceof Object && 'focus' in nativeElement);
}
function safeFocus(nativeElement) {
if (isFocusable(nativeElement)) {
nativeElement.focus();
}
}
function focus(element) {
setTimeout(() => safeFocus(element?.nativeElement));
return true;
}
function createForm(dialog, formBuilder) {
const pps = dialog.parameters;
const parms = zipObject(map(pps, p => p.id), map(pps, p => p));
const controls = mapValues(parms, p => [p.getValueForControl(), (a) => p.validator(a)]);
const form = formBuilder.group(controls);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const sub = form.valueChanges.subscribe((data) => {
// cache parm values
forEach(data, (v, k) => parms[k].setValueFromControl(v));
dialog.setParms();
});
return { form: form, dialog: dialog, parms: parms, sub: sub };
}
function accept(droppableVm, component, draggableVm) {
if (draggableVm) {
draggableVm.canDropOn(droppableVm.returnType).
then(canDrop => component.canDrop = canDrop).
catch(() => component.canDrop = false);
return true;
}
return false;
}
function dropOn(draggableVm, droppable, component) {
if (component.canDrop) {
droppable.drop(draggableVm)
.then(() => {
component.control.setValue(droppable.selectedChoice);
});
}
}
function paste(event, droppable, component, get, clear) {
const vKeyCode = 86;
const deleteKeyCode = 46;
if (event && (event.keyCode === vKeyCode && event.ctrlKey)) {
const cvm = get();
if (cvm) {
droppable.drop(cvm)
.then(() => {
component.control.setValue(droppable.selectedChoice);
});
event.preventDefault();
}
}
if (event && event.keyCode === deleteKeyCode) {
clear();
}
}
class ClickDirective {
el;
constructor(el) {
this.el = el.nativeElement;
}
leftClick = new EventEmitter();
rightClick = new EventEmitter();
onClick() {
this.leftClick.emit('event');
return false;
}
handleKey(event) {
const enterKeyCode = 13;
if (event.which === enterKeyCode) {
const trigger = event.shiftKey ? this.rightClick : this.leftClick;
trigger.emit('event');
return false;
}
return true;
}
onEnter(event) {
return this.handleKey(event);
}
onEnter1(event) {
return this.handleKey(event);
}
onContextMenu() {
this.rightClick.emit('event');
return false;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: ClickDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.10", type: ClickDirective, isStandalone: false, selector: "[nofClick]", outputs: { leftClick: "leftClick", rightClick: "rightClick" }, host: { listeners: { "click": "onClick()", "keydown": "onEnter($event)", "keypress": "onEnter1($event)", "contextmenu": "onContextMenu()" } }, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: ClickDirective, decorators: [{
type: Directive,
args: [{ selector: '[nofClick]', standalone: false }]
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { leftClick: [{
type: Output
}], rightClick: [{
type: Output
}], onClick: [{
type: HostListener,
args: ['click']
}], onEnter: [{
type: HostListener,
args: ['keydown', ['$event']]
}], onEnter1: [{
type: HostListener,
args: ['keypress', ['$event']]
}], onContextMenu: [{
type: HostListener,
args: ['contextmenu']
}] } });
function wrapAction(a) {
return {
value: a.title,
doClick: () => a.doInvoke(),
doRightClick: () => a.doInvoke(true),
show: () => true,
disabled: () => a.disabled() ? true : null,
tempDisabled: () => a.tempDisabled(),
title: () => a.description,
accesskey: null,
presentationHint: a.presentationHint,
showDialog: () => a.showDialog()
};
}
class ActionComponent {
action;
focusList;
canClick() {
return !(this.disabled() || this.tempDisabled());
}
doClick() {
if (this.canClick()) {
this.action.doClick();
}
}
doRightClick() {
if (this.canClick() && this.action.doRightClick) {
this.action.doRightClick();
}
}
class() {
return ({
tempdisabled: this.tempDisabled(),
[this.dialogClass()]: true,
});
}
show() {
return this.action.show();
}
disabled() {
return this.action.disabled();
}
tempDisabled() {
return this.action.tempDisabled();
}
dialogClass() {
return this.showDialog() ? 'has-params' : 'no-params';
}
showDialog() {
return this.action.showDialog();
}
get value() {
return this.action.value;
}
get title() {
return this.action.title();
}
focus() {
if (this.disabled()) {
return false;
}
return !!(this.focusList && this.focusList.first) && focus(this.focusList.first);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: ActionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.10", type: ActionComponent, isStandalone: false, selector: "nof-action", inputs: { action: "action" }, viewQueries: [{ propertyName: "focusList", predicate: ["focus"], descendants: true }], ngImport: i0, template: "<input #focus tabindex=\"0\" type=\"button\" nofClick (leftClick)=\"doClick()\" (rightClick)=\"doRightClick()\" [value]=\"value\" [disabled]=\"disabled()\" *ngIf=\"show()\" [title]=\"title\" [ngClass]=\"class()\">\n", styles: ["input{white-space:normal;text-align:left;cursor:pointer;background-color:transparent;outline:none;border:none;font-size:var(--font-size-2);color:var(--menu-text-color);padding:var(--space-3);font-weight:var(--font-weight-1)}input:focus,input:hover{outline-color:var(--contrast-outline-color);outline-style:solid;outline-width:1px}input:disabled{color:var(--disabled-color);outline:none}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: ClickDirective, selector: "[nofClick]", outputs: ["leftClick", "rightClick"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: ActionComponent, decorators: [{
type: Component,
args: [{ selector: 'nof-action', standalone: false, template: "<input #focus tabindex=\"0\" type=\"button\" nofClick (leftClick)=\"doClick()\" (rightClick)=\"doRightClick()\" [value]=\"value\" [disabled]=\"disabled()\" *ngIf=\"show()\" [title]=\"title\" [ngClass]=\"class()\">\n", styles: ["input{white-space:normal;text-align:left;cursor:pointer;background-color:transparent;outline:none;border:none;font-size:var(--font-size-2);color:var(--menu-text-color);padding:var(--space-3);font-weight:var(--font-weight-1)}input:focus,input:hover{outline-color:var(--contrast-outline-color);outline-style:solid;outline-width:1px}input:disabled{color:var(--disabled-color);outline:none}\n"] }]
}], propDecorators: { action: [{
type: Input,
args: [{ required: true }]
}], focusList: [{
type: ViewChildren,
args: ['focus']
}] } });
class ActionListComponent {
previousActionChildrenNames = [];
holder;
sub;
actionChildren;
set menuHolder(mh) {
this.holder = mh;
this.actionHolders = []; // clear cache;
}
get menuHolder() {
return this.holder;
}
get items() {
return this.menuHolder.menuItems;
}
actionHolders = [];
getActionHolders(menuItem) {
return map(menuItem.actions, a => wrapAction(a));
}
hasActions = (menuItem) => {
const actions = menuItem.actions;
return actions && actions.length > 0;
};
hasItems = (menuItem) => {
const items = menuItem.menuItems;
return items && items.length > 0;
};
menuName = (menuItem) => menuItem.name;
menuItems = (menuItem) => menuItem.menuItems;
menuActions = (menuItem, index) => {
if (!this.actionHolders[index]) {
this.actionHolders[index] = this.getActionHolders(menuItem);
}
return this.actionHolders[index];
};
toggleCollapsed = (menuItem) => menuItem.toggleCollapsed();
navCollapsed = (menuItem) => menuItem.navCollapsed;
displayClass = (menuItem) => ({ collapsed: menuItem.navCollapsed, open: !menuItem.navCollapsed, rootMenu: !menuItem.name });
classes(action) {
const hint = action.presentationHint ?? '';
return hint.trim();
}
focusFromIndex(actions, index = 0) {
const toFocus = actions.toArray().slice(index);
if (toFocus && toFocus.length > 0) {
// until first element returns true
some(toFocus, i => i.focus());
}
}
focus(actions) {
if (actions && actions.length > 0) {
const actionChildrenNames = map(actions.toArray(), a => a.action.value);
const newActions = difference(actionChildrenNames, this.previousActionChildrenNames);
let index = 0;
if (newActions && newActions.length > 0) {
const firstAction = first(newActions);
index = findIndex(actions.toArray(), a => a.action.value === firstAction);
index = index < 0 ? 0 : index;
}
this.previousActionChildrenNames = actionChildrenNames;
this.focusFromIndex(actions, index);
}
}
ngAfterViewInit() {
this.focus(this.actionChildren);
this.sub = this.actionChildren?.changes.subscribe((ql) => this.focus(ql));
}
ngOnDestroy() {
safeUnsubscribe(this.sub);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: ActionListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.10", type: ActionListComponent, isStandalone: false, selector: "nof-action-list", inputs: { menuHolder: "menuHolder" }, viewQueries: [{ propertyName: "actionChildren", predicate: ActionComponent, descendants: true }], ngImport: i0, template: "<ng-container *ngFor=\"let menu of items; let i = index\">\n\n <div *ngIf=\"menuName(menu)\" (click)=\"toggleCollapsed(menu)\" (keydown.enter)=\"toggleCollapsed(menu)\" class=\"submenu\" [ngSwitch]=\"navCollapsed(menu)\" tabindex=\"0\">\n {{menuName(menu)}}\n <div *ngSwitchCase=\"true\" (keydown.enter)=\"toggleCollapsed(menu)\" class=\"icon-expand\" tabindex=\"0\"></div>\n <div *ngSwitchCase=\"false\" (keydown.enter)=\"toggleCollapsed(menu)\" class=\"icon-collapse\" tabindex=\"0\"></div>\n </div>\n <div *ngIf=\"!navCollapsed(menu)\" class=\"menuitem\" [ngClass]=\"displayClass(menu)\">\n <ng-container *ngIf=\"hasActions(menu)\">\n <ng-container *ngFor=\"let action of menuActions(menu, i)\">\n <nof-action [ngClass]=\"classes(action)\" [action]=\"action\"></nof-action>\n </ng-container>\n </ng-container>\n <ng-container *ngIf=\"hasItems(menu)\">\n <nof-action-list [menuHolder]=\"menu\"></nof-action-list>\n </ng-container>\n </div>\n</ng-container>\n", styles: [":host{float:left;margin-bottom:var(--space-5);display:block;margin-right:var(--space-4);background-color:var(--menu-background-color)}nof-action,.submenu{display:block;cursor:pointer;outline:none;margin-right:var(--space-5);width:var(--action-width)}.submenu{padding:var(--space-3);color:var(--menu-text-color)}.submenu:hover{outline-style:solid;outline-width:1px;outline-color:var(--default-contrast-color)}.collapsed{display:none}.open{margin-left:var(--space-4)}.open.rootMenu{margin-left:0}.icon-expand:before{content:var(--submenu-expand-icon)}.icon-collapse:before{content:var(--submenu-collapse-icon)}.icon-expand,.icon-collapse{font-size:var(--font-size-1)}.icon-expand:hover,.icon-collapse:hover{outline-color:var(--contrast-outline-color);outline-width:1px}[class^=icon-],[class*=\" icon-\"]{font-family:iconFont;font-weight:var(--font-weight-1);font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;display:inline-block;width:auto;height:auto;line-height:normal;vertical-align:baseline;background-image:none;background-position:0% 0%;background-repeat:repeat;margin-top:0;position:relative}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "component", type: ActionListComponent, selector: "nof-action-list", inputs: ["menuHolder"] }, { kind: "component", type: ActionComponent, selector: "nof-action", inputs: ["action"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: ActionListComponent, decorators: [{
type: Component,
args: [{ selector: 'nof-action-list', standalone: false, template: "<ng-container *ngFor=\"let menu of items; let i = index\">\n\n <div *ngIf=\"menuName(menu)\" (click)=\"toggleCollapsed(menu)\" (keydown.enter)=\"toggleCollapsed(menu)\" class=\"submenu\" [ngSwitch]=\"navCollapsed(menu)\" tabindex=\"0\">\n {{menuName(menu)}}\n <div *ngSwitchCase=\"true\" (keydown.enter)=\"toggleCollapsed(menu)\" class=\"icon-expand\" tabindex=\"0\"></div>\n <div *ngSwitchCase=\"false\" (keydown.enter)=\"toggleCollapsed(menu)\" class=\"icon-collapse\" tabindex=\"0\"></div>\n </div>\n <div *ngIf=\"!navCollapsed(menu)\" class=\"menuitem\" [ngClass]=\"displayClass(menu)\">\n <ng-container *ngIf=\"hasActions(menu)\">\n <ng-container *ngFor=\"let action of menuActions(menu, i)\">\n <nof-action [ngClass]=\"classes(action)\" [action]=\"action\"></nof-action>\n </ng-container>\n </ng-container>\n <ng-container *ngIf=\"hasItems(menu)\">\n <nof-action-list [menuHolder]=\"menu\"></nof-action-list>\n </ng-container>\n </div>\n</ng-container>\n", styles: [":host{float:left;margin-bottom:var(--space-5);display:block;margin-right:var(--space-4);background-color:var(--menu-background-color)}nof-action,.submenu{display:block;cursor:pointer;outline:none;margin-right:var(--space-5);width:var(--action-width)}.submenu{padding:var(--space-3);color:var(--menu-text-color)}.submenu:hover{outline-style:solid;outline-width:1px;outline-color:var(--default-contrast-color)}.collapsed{display:none}.open{margin-left:var(--space-4)}.open.rootMenu{margin-left:0}.icon-expand:before{content:var(--submenu-expand-icon)}.icon-collapse:before{content:var(--submenu-collapse-icon)}.icon-expand,.icon-collapse{font-size:var(--font-size-1)}.icon-expand:hover,.icon-collapse:hover{outline-color:var(--contrast-outline-color);outline-width:1px}[class^=icon-],[class*=\" icon-\"]{font-family:iconFont;font-weight:var(--font-weight-1);font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;display:inline-block;width:auto;height:auto;line-height:normal;vertical-align:baseline;background-image:none;background-position:0% 0%;background-repeat:repeat;margin-top:0;position:relative}\n"] }]
}], propDecorators: { actionChildren: [{
type: ViewChildren,
args: [ActionComponent]
}], menuHolder: [{
type: Input
}] } });
class ActionBarComponent {
actions;
set menuHolder(mhvm) {
const menuItems = mhvm.menuItems;
const avms = flatten(map(menuItems || [], (mi) => mi.actions));
this.actions = map(avms, a => wrapAction(a));
}
actionChildren;
sub;
classes(action) {
const hint = action.presentationHint ?? '';
return hint.trim();
}
focusOnFirstAction(actions) {
if (actions) {
// until first element returns true
some(actions.toArray(), i => i.focus());
}
}
ngAfterViewInit() {
this.focusOnFirstAction(this.actionChildren);
this.sub = this.actionChildren?.changes.subscribe((ql) => this.focusOnFirstAction(ql));
}
ngOnDestroy() {
safeUnsubscribe(this.sub);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: ActionBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.10", type: ActionBarComponent, isStandalone: false, selector: "nof-action-bar", inputs: { actions: "actions", menuHolder: "menuHolder" }, viewQueries: [{ propertyName: "actionChildren", predicate: ActionComponent, descendants: true }], ngImport: i0, template: "<nof-action [ngClass]=\"classes(action)\" *ngFor=\"let action of actions\" [action]=\"action\"></nof-action>\n\n", styles: [":host{display:block}nof-action{outline:none;display:block;float:left;padding:var(--space-3);margin-left:var(--space-1);margin-right:var(--space-4);margin-bottom:var(--space-3);font-weight:var(--font-weight-2)er;font-size:var(--font-size-2)}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: ActionComponent, selector: "nof-action", inputs: ["action"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: ActionBarComponent, decorators: [{
type: Component,
args: [{ selector: 'nof-action-bar', standalone: false, template: "<nof-action [ngClass]=\"classes(action)\" *ngFor=\"let action of actions\" [action]=\"action\"></nof-action>\n\n", styles: [":host{display:block}nof-action{outline:none;display:block;float:left;padding:var(--space-3);margin-left:var(--space-1);margin-right:var(--space-4);margin-bottom:var(--space-3);font-weight:var(--font-weight-2)er;font-size:var(--font-size-2)}\n"] }]
}], propDecorators: { actions: [{
type: Input
}], menuHolder: [{
type: Input
}], actionChildren: [{
type: ViewChildren,
args: [ActionComponent]
}] } });
// updated by build do not update manually or change name or regex may not match
const clientVersion = '17.0.0';
class ApplicationPropertiesComponent {
viewModelFactory;
constructor(viewModelFactory) {
this.viewModelFactory = viewModelFactory;
}
get applicationName() {
return this.applicationProperties?.applicationName ?? '';
}
get userName() {
return this.applicationProperties?.userName ?? '';
}
get serverUrl() {
return this.applicationProperties?.serverUrl ?? '';
}
get implVersion() {
return this.applicationProperties?.serverVersion?.implVersion ?? '';
}
get apiVersion() {
return this.applicationProperties?.serverVersion?.specVersion ?? '';
}
get appVersion() {
return this.applicationProperties?.serverVersion?.appVersion ?? '';
}
get clientVersion() {
return clientVersion;
}
applicationProperties;
ngOnInit() {
this.applicationProperties = this.viewModelFactory.applicationPropertiesViewModel();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: ApplicationPropertiesComponent, deps: [{ token: i3.ViewModelFactoryService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.10", type: ApplicationPropertiesComponent, isStandalone: false, selector: "nof-application-properties", ngImport: i0, template: "<div id=\"pane1\" class=\"single\">\n <div class=\"applicationproperties\">\n <div class=\"header\">\n <div class=\"title\">Application Properties</div>\n </div>\n <div class=\"main-column\">\n <div class=\"properties\">\n <div class=\"property\">\n Application Name: {{applicationName}}\n </div>\n <div class=\"property\">\n User Name: {{userName}}\n </div>\n <div class=\"property\">\n Server Url: {{serverUrl}}\n </div>\n <div class=\"property\">\n Server API version: {{apiVersion}}\n </div>\n <div class=\"property\">\n Server Framework version: {{implVersion}}\n </div>\n <div class=\"property\">\n Server Application version: {{appVersion}}\n </div>\n <div class=\"property\">\n Client version: {{clientVersion}}\n </div>\n </div>\n </div>\n </div>\n</div>\n", styles: [":host{display:block;margin-left:var(--space-5);padding-left:var(--space-5);height:100%;overflow-y:auto}.header{display:block;margin-bottom:var(--space-5);overflow:hidden;color:var(--contrast-text-color);font-size:var(--font-size-4);font-weight:var(--font-weight-2);background-color:var(--header-background-color)}.title{position:relative;margin-left:var(--space-1);padding-left:var(--space-3);padding-right:var(--space-3);margin-right:var(--space-5);margin-top:var(--space-1);display:inline-block}.properties{color:var(--default-text-color);font-size:var(--font-size-2);font-weight:var(--font-weight-1);width:var(--field-width);padding:var(--space-3);margin-bottom:var(--space-5)}\n"] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: ApplicationPropertiesComponent, decorators: [{
type: Component,
args: [{ selector: 'nof-application-properties', standalone: false, template: "<div id=\"pane1\" class=\"single\">\n <div class=\"applicationproperties\">\n <div class=\"header\">\n <div class=\"title\">Application Properties</div>\n </div>\n <div class=\"main-column\">\n <div class=\"properties\">\n <div class=\"property\">\n Application Name: {{applicationName}}\n </div>\n <div class=\"property\">\n User Name: {{userName}}\n </div>\n <div class=\"property\">\n Server Url: {{serverUrl}}\n </div>\n <div class=\"property\">\n Server API version: {{apiVersion}}\n </div>\n <div class=\"property\">\n Server Framework version: {{implVersion}}\n </div>\n <div class=\"property\">\n Server Application version: {{appVersion}}\n </div>\n <div class=\"property\">\n Client version: {{clientVersion}}\n </div>\n </div>\n </div>\n </div>\n</div>\n", styles: [":host{display:block;margin-left:var(--space-5);padding-left:var(--space-5);height:100%;overflow-y:auto}.header{display:block;margin-bottom:var(--space-5);overflow:hidden;color:var(--contrast-text-color);font-size:var(--font-size-4);font-weight:var(--font-weight-2);background-color:var(--header-background-color)}.title{position:relative;margin-left:var(--space-1);padding-left:var(--space-3);padding-right:var(--space-3);margin-right:var(--space-5);margin-top:var(--space-1);display:inline-block}.properties{color:var(--default-text-color);font-size:var(--font-size-2);font-weight:var(--font-weight-1);width:var(--field-width);padding:var(--space-3);margin-bottom:var(--space-5)}\n"] }]
}], ctorParameters: () => [{ type: i3.ViewModelFactoryService }] });
class PaneComponent {
activatedRoute;
urlManager;
context;
constructor(activatedRoute, urlManager, context) {
this.activatedRoute = activatedRoute;
this.urlManager = urlManager;
this.context = context;
}
activatedRouteDataSub;
paneRouteDataSub;
lastPaneRouteData;
// pane API
paneId;
paneType;
paneIdName;
arData;
onChild() {
setTimeout(() => this.paneType = 'split');
}
onChildless() {
setTimeout(() => this.paneType = 'single');
}
doSetup(routeData) {
return !routeData.isEqual(this.lastPaneRouteData);
}
ngOnInit() {
this.activatedRouteDataSub = this.activatedRoute.data.subscribe(d => {
const data = d;
this.arData = data;
this.paneId = data.pane;
this.paneType = data.paneType;
this.paneIdName = this.paneId === 1 ? 'pane1' : 'pane2';
if (!this.paneRouteDataSub) {
this.paneRouteDataSub =
this.urlManager.getPaneRouteDataObservable(this.paneId)
.subscribe((paneRouteData) => {
if (!paneRouteData.isEqualIgnoringReload(this.lastPaneRouteData)) {
// only remove messages if something more than reload flag has changed
this.context.clearMessages();
this.context.clearWarnings();
}
if (this.doSetup(paneRouteData)) {
this.lastPaneRouteData = paneRouteData;
this.setup(paneRouteData);
}
});
}
});
}
ngOnDestroy() {
safeUnsubscribe(this.activatedRouteDataSub);
safeUnsubscribe(this.paneRouteDataSub);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: PaneComponent, deps: [{ token: i1$1.ActivatedRoute }, { token: i2.UrlManagerService }, { token: i2.ContextService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.10", type: PaneComponent, isStandalone: true, selector: "ng-component", ngImport: i0, template: '<div></div>', isInline: true });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: PaneComponent, decorators: [{
type: Component,
args: [{ template: '<div></div>' }]
}], ctorParameters: () => [{ type: i1$1.ActivatedRoute }, { type: i2.UrlManagerService }, { type: i2.ContextService }] });
class AttachmentComponent extends PaneComponent {
viewModelFactory;
error;
configService;
constructor(activatedRoute, urlManager, viewModelFactory, context, error, configService) {
super(activatedRoute, urlManager, context);
this.viewModelFactory = viewModelFactory;
this.error = error;
this.configService = configService;
}
// template API
image;
title = '';
setup(routeData) {
const oid = Ro.ObjectIdWrapper.fromObjectId(routeData.objectId, this.configService.config.keySeparator);
this.context.getObject(routeData.paneId, oid, routeData.interactionMode)
.then((object) => {
const attachmentId = routeData.attachmentId;
const attachment = attachmentId ? object.propertyMember(attachmentId) : undefined;
if (attachment) {
const avm = this.viewModelFactory.attachmentViewModel(attachment, routeData.paneId);
if (avm) {
avm.setImage(this);
}
}
})
.catch((reject) => this.error.handleError(reject));
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AttachmentComponent, deps: [{ token: i1$1.ActivatedRoute }, { token: i2.UrlManagerService }, { token: i3.ViewModelFactoryService }, { token: i2.ContextService }, { token: i2.ErrorService }, { token: i2.ConfigService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.10", type: AttachmentComponent, isStandalone: false, selector: "nof-attachment", usesInheritance: true, ngImport: i0, template: "<div [attr.id]=\"paneIdName\" [ngClass]=\"paneType\">\n <div class=\"attachment view\">\n <div class=\"reference\">\n <img *ngIf=\"image\" src=\"{{image}}\" alt=\"{{title}}\" />\n </div>\n </div>\n</div>\n<router-outlet (activate)=\"onChild()\" (deactivate)=\"onChildless()\"></router-outlet>\n", styles: [".attachment{justify-content:center;align-items:center;display:flex;height:100%}img{max-width:100%;height:auto}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AttachmentComponent, decorators: [{
type: Component,
args: [{ selector: 'nof-attachment', standalone: false, template: "<div [attr.id]=\"paneIdName\" [ngClass]=\"paneType\">\n <div class=\"attachment view\">\n <div class=\"reference\">\n <img *ngIf=\"image\" src=\"{{image}}\" alt=\"{{title}}\" />\n </div>\n </div>\n</div>\n<router-outlet (activate)=\"onChild()\" (deactivate)=\"onChildless()\"></router-outlet>\n", styles: [".attachment{justify-content:center;align-items:center;display:flex;height:100%}img{max-width:100%;height:auto}\n"] }]
}], ctorParameters: () => [{ type: i1$1.ActivatedRoute }, { type: i2.UrlManagerService }, { type: i3.ViewModelFactoryService }, { type: i2.ContextService }, { type: i2.ErrorService }, { type: i2.ConfigService }] });
class AttachmentPropertyComponent {
error;
urlManager;
clickHandlerService;
constructor(error, urlManager, clickHandlerService) {
this.error = error;
this.urlManager = urlManager;
this.clickHandlerService = clickHandlerService;
}
attach = null;
set attachment(avm) {
this.attach = avm;
this.setup();
}
get attachment() {
return this.attach;
}
title = 'Empty';
image;
doAttachmentClick = (right) => {
if (this.attachment.empty && !this.image) {
return;
}
if (this.attachment.displayInline()) {
this.urlManager.setAttachment(this.attachment.link, this.clickHandlerService.pane(this.attachment.onPaneId, right));
}
else {
this.attachment.downloadFile()
.then(blob => {
const burl = URL.createObjectURL(blob);
window.open(burl);
})
.catch((reject) => this.error.handleError(reject));
}
};
setup() {
if (this.attachment) {
if (this.attachment.displayInline()) {
this.attachment.setImage(this);
}
else {
this.attachment.setTitle(this);
}
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AttachmentPropertyComponent, deps: [{ token: i2.ErrorService }, { token: i2.UrlManagerService }, { token: i2.ClickHandlerService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.10", type: AttachmentPropertyComponent, isStandalone: false, selector: "nof-attachment-property", inputs: { attachment: "attachment" }, ngImport: i0, template: "<div *ngIf=\"attachment\" class=\"reference file-attachment\" nofClick (leftClick)=\"doAttachmentClick()\" (rightClick)=\"doAttachmentClick(true)\" tabindex=\"0\">\n <div *ngIf=\"!attachment.empty && !image\">{{title}}</div>\n <img *ngIf=\"!attachment.empty && image\" src=\"{{image}}\" alt=\"{{title}}\" />\n <div *ngIf=\"attachment.empty\">{{title}}</div>\n</div>", styles: [".reference{cursor:pointer}img{max-width:var(--field-value-width);max-height:100px}.value{display:block;float:left;width:var(--field-value-width);padding-left:var(--space-3);padding-right:var(--space-3);margin:var(--space-1)}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: ClickDirective, selector: "[nofClick]", outputs: ["leftClick", "rightClick"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: AttachmentPropertyComponent, decorators: [{
type: Component,
args: [{ selector: 'nof-attachment-property', standalone: false, template: "<div *ngIf=\"attachment\" class=\"reference file-attachment\" nofClick (leftClick)=\"doAttachmentClick()\" (rightClick)=\"doAttachmentClick(true)\" tabindex=\"0\">\n <div *ngIf=\"!attachment.empty && !image\">{{title}}</div>\n <img *ngIf=\"!attachment.empty && image\" src=\"{{image}}\" alt=\"{{title}}\" />\n <div *ngIf=\"attachment.empty\">{{title}}</div>\n</div>", styles: [".reference{cursor:pointer}img{max-width:var(--field-value-width);max-height:100px}.value{display:block;float:left;width:var(--field-value-width);padding-left:var(--space-3);padding-right:var(--space-3);margin:var(--space-1)}\n"] }]
}], ctorParameters: () => [{ type: i2.ErrorService }, { type: i2.UrlManagerService }, { type: i2.ClickHandlerService }], propDecorators: { attachment: [{
type: Input
}] } });
class BaseDialogComponent {
viewModelFactory;
error;
context;
formBuilder;
constructor(viewModelFactory, error, context, formBuilder) {
this.viewModelFactory = viewModelFactory;
this.error = error;
this.context = context;
this.formBuilder = formBuilder;
}
parentViewModel;
parms;
formSub;
sub;
createFormSub;
set parent(parent) {
this.parentChanged = this.parentViewModel !== parent;
this.parentViewModel = parent;
}
get parent() {
return this.parentViewModel;
}
currentDialogId;
parentChanged = false;
set selectedDialogId(id) {
this.currentDialogId = id;
}
get selectedDialogId() {
return this.currentDialogId;
}
dialog = null;
form;
get title() {
const dialog = this.dialog;
return dialog ? dialog.title : '';
}
get message() {
const dialog = this.dialog;
return dialog ? dialog.getMessage() : '';
}
get parameters() {
const dialog = this.dialog;
return dialog ? dialog.parameters : [];
}
get tooltip() {
const dialog = this.dialog;
return dialog ? dialog.tooltip() : '';
}
onSubmit(right) {
if (this.dialog) {
forEach(this.parms, (p, _) => {
if (p.isEditable) {
const newValue = this.form.value[p.id];
p.setValueFromControl(newValue);
}
});
this.dialog.doInvoke(right);
}
}
close = () => {
if (this.dialog) {
this.dialog.doCloseReplaceHistory();
this.dialog = null;
}
};
createForm(dialog) {
safeUnsubscribe(this.formSub);
safeUnsubscribe(this.createFormSub);
({ form: this.form, dialog: this.dialog, parms: this.parms, sub: this.createFormSub } = createForm(dialog, this.formBuilder));
this.formSub = this.form.valueChanges.subscribe((_) => this.onValueChanged());
}
onValueChanged() {
if (this.dialog) {
// clear messages if dialog changes
this.dialog.resetMessage();
this.context.clearMessages();
this.context.clearWarnings();
}
}
closeExistingDialog() {
if (this.dialog) {
if (this.dialog.id !== this.currentDialogId) {
this.dialog.doCloseKeepHistory();
}
else {
this.dialog.doCloseKeepUrl();
}
this.dialog = null;
}
}
getDialog() {
// if it's the same dialog just return
if (this.parent && this.currentDialogId) {
if (!this.parentChanged && this.dialog && this.dialog.id === this.currentDialogId) {
return;
}
this.parentChanged = false;
const p = this.parent;
let action = null;
let actionViewModel = null;
if (p instanceof MenuViewModel) {
action = p.menuRep.actionMember(this.currentDialogId);
}
if (p instanceof DomainObjectViewModel && p.domainObject.hasActionMember(this.currentDialogId)) {
action = p.domainObject.actionMember(this.currentDialogId);
}
if (p instanceof ListViewModel) {
action = p.actionMember(this.currentDialogId);
actionViewModel = find(p.actions, a => a.actionRep.actionId() === this.currentDialogId) || null;
}
if (p instanceof CollectionViewModel && p.hasMatchingLocallyContributedAction(this.currentDialogId)) {
action = p.actionMember(this.currentDialogId);
actionViewModel = find(p.actions, a => a.actionRep.actionId() === this.currentDialogId) || null;
}
if (action) {
this.context.getInvokableAction(action)
.then(details => {
// only if we still have a dialog (may have beenn removed while getting invokable action)
if (this.currentDialogId) {
// must be a change
this.closeExistingDialog();
const dialogViewModel = this.viewModelFactory.dialogViewModel(this.parent.routeData, details, actionViewModel, false);
this.createForm(dialogViewModel);
}
})
.catch((reject) => {
this.error.handleError(reject);
});
}
else {
this.closeExistingDialog();
}
}
else {
this.closeExistingDialog();
}
}
ngOnDestroy() {
safeUnsubscribe(this.createFormSub);
safeUnsubscribe(this.formSub);
safeUnsubscribe(this.sub);
this.closeExistingDialog();
}
ngOnChanges() {
this.getDialog();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: BaseDialogComponent, deps: [{ token: i3.ViewModelFactoryService }, { token: i2.ErrorService }, { token: i2.ContextService }, { token: i4.FormBuilder }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.10", type: BaseDialogComponent, isStandalone: true, selector: "ng-component", inputs: { selectedDialogId: "selectedDialogId" }, usesOnChanges: true, ngImport: i0, template: '<div></div>', isInline: true });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: BaseDialogComponent, decorators: [{
type: Component,
args: [{ template: '<div></div>' }]
}], ctorParameters: () => [{ type: i3.ViewModelFactoryService }, { type: i2.ErrorService }, { type: i2.ContextService }, { type: i4.FormBuilder }], propDecorators: { selectedDialogId: [{
type: Input
}] } });
class FieldComponent {
loggerService;
renderer;
dragAndDrop;
constructor(loggerService, renderer, dragAndDrop) {
this.loggerService = loggerService;
this.renderer = renderer;
this.dragAndDrop = dragAndDrop;
}
set formGroup(fm) {
this.formGrp = fm;
this.formGrp.valueChanges.pipe(debounceTime(200)).subscribe(_ => this.onValueChanged());
this.onValueChanged(); // (re)set validation messages now
}
get formGroup() {
return this.formGrp;
}
get message() {
return this.model.getMessage();
}
get isBoolean() {
return this.model.returnType === 'boolean';
}
get subject() {
if (!this.bSubject) {
const initialValue = this.control.value;
this.bSubject = new BehaviorSubject(initialValue);
this.sub = this.control.valueChanges.subscribe((data) => {
this.bSubject.next(data);
});
}
return this.bSubject;
}
formGrp;
vmParent;
model;
isConditionalChoices;
isAutoComplete;
bSubject;
sub;
lastArgs;
control;
currentOptions = [];
pArgs;
paneId;
canDrop = false;
dragOver = false;
init(vmParent, vm, control) {
this.vmParent = vmParent;
this.model = vm;
this.control = control;
this.paneId = this.model.onPaneId;
this.isConditionalChoices = (this.model.entryType === Ro.EntryType.ConditionalChoices ||
this.model.entryType === Ro.EntryType.MultipleConditionalChoices);
this.isAutoComplete = this.model.entryType === Ro.EntryType.AutoComplete;
if (this.isConditionalChoices) {
this.pArgs = omit(this.model.promptArguments, 'x-ro-nof-members');
this.populateDropdown();
}
}
get accept() {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const _this = this;
return (cdkDrag, _cdkDropList) => {
return accept(_this.model, _this, cdkDrag.data);
};
}
drop(event) {
const cdkDrag = event.item;
if (event.isPointerOverContainer) {
dropOn(cdkDrag.data, this.model, this);
}
this.canDrop = false;
this.dragOver = false;
}
exit() {
this.canDrop = false;
this.dragOver = false;
}
enter() {
this.dragOver = true;
}
isDomainObjectViewModel(object) {
return !!(object && object instanceof Object && 'properties' in object);
}
mapValues(args, parmsOrProps) {
return mapValues(args, (v, n) => {
const pop = find(parmsOrProps, p => p.argId === n);
return pop.getValue();
});
}
populateArguments() {
const dialog = this.vmParent;
const object = this.vmParent;
if (!dialog && !object) {
this.loggerService.throw('FieldComponent:populateArguments Expect dialog or object');
}
let parmsOrProps;
if (this.isDomainObjectViewModel(object)) {
parmsOrProps = object.properties;
}
else {
parmsOrProps = dialog.parameters;
}
return this.mapValues(this.pArgs, parmsOrProps);
}
argsChanged(newArgs) {
const same = this.lastArgs &&
keys(this.lastArgs).length === keys(newArgs).length &&
every(this.lastArgs, (v, k) => newArgs[k].toValueString() === v.toValueString());
this.lastArgs = newArgs;
return !same;
}
populateDropdown() {
const nArgs = this.populateArguments();
if (this.argsChanged(nArgs)) {
const prompts = this.model.conditionalChoices;
if (prompts) {
prompts(nArgs).
then((cvms) => {
// if unchanged return
if (cvms.length === this.currentOptions.length && every(cvms, (c, i) => c.equals(this.currentOptions[i]))) {
return;
}
this.model.choices = cvms;
this.currentOptions = cvms;
if (this.isConditionalChoices) {
// need to reset control to find the selected options
if (this.model.entryType === Ro.EntryType.MultipleConditionalChoices) {
this.control.reset(this.model.selectedMultiChoices);
}
else {
this.control.reset(this.model.selectedChoice);
}
}
}).
catch(() => {
// error clear everything
this.model.selectedChoice = null;
this.currentOptions = [];
});
}
}
}
onChange() {
if (this.isConditionalChoices) {
this.populateDropdown();
}
else if (this.isAutoComplete) {
this.populateAutoComplete();
}
else if (this.isBoolean) {
this.populateBoolean();
}
}
onValueChanged() {
if (this.model) {
this.onChange();
}
}
populateAutoComplete() {
const input = this.control.value;
if (input instanceof ChoiceViewModel) {
return;
}
const prompt = this.model.prompt;
if (prompt && input && input.length > 0 && input.length >= (this.model.minLength ?? 0)) {
prompt(input)
.then((cvms) => {
if (cvms.length === this.currentOptions.length && every(cvms, (c, i) => c.equals(this.currentOptions[i]))) {
return;
}
this.model.choices = cvms;
this.currentOptions = cvms;
this.model.selectedChoice = null;
})
.catch(() => {
this.model.choices = [];
this.currentOptions = [];
this.model.selectedChoice = null;
});
}
else {
this.model.choices = [];
this.currentOptions = [];
this.model.selectedChoice = null;
}
}
populateBoolean() {
// editable booleans only
if (this.isBoolean && this.control) {
const input = this.control.value;
const element = this.checkboxList?.first.nativeElement;
if (input == null) {
thi