From c5d7b99a7fd59a91dfc75b62cd20e73448eb19fe Mon Sep 17 00:00:00 2001 From: "Moises E. Puyosa" Date: Fri, 10 Nov 2023 12:27:20 -0500 Subject: [PATCH 1/2] Fix #343 - Panels Collapsible --- .../common/src/lib/metadata/metadata.model.ts | 9 +- .../record-content.component.html | 4 +- .../record-content.component.ts | 35 ++++-- .../record-content/record-content.module.ts | 4 +- core/app/core/src/lib/core.ts | 2 + .../pipes/toObservable/toObservable.module.ts | 44 +++++++ .../pipes/toObservable/toObservable.pipe.ts | 37 ++++++ .../store/create-view/create-view.store.ts | 8 +- .../views/record/adapters/actions.adapter.ts | 12 +- .../record/adapters/record-content.adapter.ts | 62 +--------- .../store/record-view/record-view.store.ts | 115 ++++++++++++++++-- 11 files changed, 236 insertions(+), 96 deletions(-) create mode 100644 core/app/core/src/lib/pipes/toObservable/toObservable.module.ts create mode 100644 core/app/core/src/lib/pipes/toObservable/toObservable.pipe.ts diff --git a/core/app/common/src/lib/metadata/metadata.model.ts b/core/app/common/src/lib/metadata/metadata.model.ts index ba1134bd33..4e1267f8ec 100644 --- a/core/app/common/src/lib/metadata/metadata.model.ts +++ b/core/app/common/src/lib/metadata/metadata.model.ts @@ -52,6 +52,7 @@ export interface Panel { displayState: BehaviorSubject; display$: Observable; meta: TabDefinition; + isCollapsed: boolean; } export interface PanelRow { @@ -63,7 +64,7 @@ export interface PanelCell extends ViewFieldDefinition { } export interface ViewFieldDefinitionMap { - [key: string]: ViewFieldDefinition + [key: string]: ViewFieldDefinition; } export interface TabDefinitions { @@ -86,12 +87,12 @@ export interface LogicDefinition { modes: Array; params: { activeOnFields?: { - [key:string]: LogicRuleValues[]; - } + [key: string]: LogicRuleValues[]; + }; displayState?: boolean; fieldDependencies: Array; asyncProcessHandler?: string; - } + }; } export interface LogicRuleValues{ diff --git a/core/app/core/src/lib/components/record-content/record-content.component.html b/core/app/core/src/lib/components/record-content/record-content.component.html index 38ea2758aa..bb6a8a5275 100644 --- a/core/app/core/src/lib/components/record-content/record-content.component.html +++ b/core/app/core/src/lib/components/record-content/record-content.component.html @@ -29,7 +29,7 @@
- +
@@ -64,7 +64,7 @@
- +
diff --git a/core/app/core/src/lib/components/record-content/record-content.component.ts b/core/app/core/src/lib/components/record-content/record-content.component.ts index 688b3ac627..e507db84d4 100644 --- a/core/app/core/src/lib/components/record-content/record-content.component.ts +++ b/core/app/core/src/lib/components/record-content/record-content.component.ts @@ -58,8 +58,10 @@ export class RecordContentComponent implements OnInit, OnDestroy { })); this.subs.push(this.dataSource.getPanels().subscribe(panels => { this.panels = [...panels]; - if (this?.config?.layout === 'tabs') { - this.updatePanelsArray(); + if (this?.config?.layout === 'panels') { + this.updatePanelCollapseState(); + } else { + this.updatePanelsInTabs(); } })); this.subs.push(this.dataSource.getRecord().subscribe(record => { @@ -74,7 +76,7 @@ export class RecordContentComponent implements OnInit, OnDestroy { this.subs.forEach(sub => sub.unsubscribe()); } - updatePanelsArray(): void { + updatePanelsInTabs(): void { let tempPanels = []; let prevTabKey = ''; @@ -82,20 +84,11 @@ export class RecordContentComponent implements OnInit, OnDestroy { const tabDefs = this.mapTabDefs(); - if(!Object.keys(tabDefs ?? {}).length) { - Object.keys(panelsMap ?? {}).forEach(key => { - tabDefs[key.toUpperCase()] = { - newTab: true, - panelDefault: 'expanded' - }; - }); - } - Object.keys(tabDefs).forEach(tabDefKey => { const tabDef = tabDefs[tabDefKey]; if (isTrue(tabDef.newTab)) { - tempPanels = [...tempPanels, panelsMap[tabDefKey]] + tempPanels = [...tempPanels, panelsMap[tabDefKey]]; prevTabKey = tabDefKey; } else { const prevTab = tabDefs[prevTabKey]; @@ -126,12 +119,28 @@ export class RecordContentComponent implements OnInit, OnDestroy { } + updatePanelCollapseState(): void { + const panelMap = this.buildPanelMap(); + + this.panels.forEach(panel => { + const panelKey = panel.key.toUpperCase(); + if (panelMap[panelKey]) { + panel.isCollapsed = panelMap[panelKey].isCollapsed; + } + }); + } + buildPanelMap(): any { const panelMap = {}; this.panels.forEach(panel => { + let isCollapsed = false; panel.label = panel?.label?.toUpperCase() ?? ''; const panelKey = panel?.key?.toUpperCase() ?? ''; + if (panel.meta.panelDefault === 'collapsed') { + isCollapsed = true; + } + panel.isCollapsed = isCollapsed; panelMap[panelKey] = panel; }); diff --git a/core/app/core/src/lib/components/record-content/record-content.module.ts b/core/app/core/src/lib/components/record-content/record-content.module.ts index 0554e2bead..d170b255c5 100644 --- a/core/app/core/src/lib/components/record-content/record-content.module.ts +++ b/core/app/core/src/lib/components/record-content/record-content.module.ts @@ -30,6 +30,7 @@ import {NgbModule} from '@ng-bootstrap/ng-bootstrap'; import {RecordContentComponent} from './record-content.component'; import {PanelModule} from '../panel/panel.module'; import {FieldLayoutModule} from '../field-layout/field-layout.module'; +import {ToObservableModule} from '../../pipes/toObservable/toObservable.module'; @NgModule({ @@ -43,7 +44,8 @@ import {FieldLayoutModule} from '../field-layout/field-layout.module'; CommonModule, PanelModule, NgbModule, - FieldLayoutModule + FieldLayoutModule, + ToObservableModule, ] }) export class RecordContentModule { diff --git a/core/app/core/src/lib/core.ts b/core/app/core/src/lib/core.ts index ab8b035733..8bdfa4d182 100644 --- a/core/app/core/src/lib/core.ts +++ b/core/app/core/src/lib/core.ts @@ -429,6 +429,8 @@ export * from './pipes/format-number/format-number.module'; export * from './pipes/format-number/format-number.pipe'; export * from './pipes/html-sanitize/html-sanitize.module'; export * from './pipes/html-sanitize/html-sanitize.pipe'; +export * from './pipes/toObservable/toObservable.module'; +export * from './pipes/toObservable/toObservable.pipe'; export * from './services/actions/base-action-manager.service'; export * from './services/actions/base-action.adapter'; export * from './services/actions/base-record-action.adapter'; diff --git a/core/app/core/src/lib/pipes/toObservable/toObservable.module.ts b/core/app/core/src/lib/pipes/toObservable/toObservable.module.ts new file mode 100644 index 0000000000..bb2970e1e0 --- /dev/null +++ b/core/app/core/src/lib/pipes/toObservable/toObservable.module.ts @@ -0,0 +1,44 @@ +/** + * SuiteCRM is a customer relationship management program developed by SalesAgility Ltd. + * Copyright (C) 2023 SalesAgility Ltd. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SALESAGILITY, SALESAGILITY DISCLAIMS THE + * WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * In accordance with Section 7(b) of the GNU Affero General Public License + * version 3, these Appropriate Legal Notices must retain the display of the + * "Supercharged by SuiteCRM" logo. If the display of the logos is not reasonably + * feasible for technical reasons, the Appropriate Legal Notices must display + * the words "Supercharged by SuiteCRM". + */ + +import {NgModule} from '@angular/core'; +import {CommonModule} from '@angular/common'; +import {ToObservablePipe} from './toObservable.pipe'; + + +@NgModule({ + declarations: [ + ToObservablePipe + ], + exports: [ + ToObservablePipe + ], + imports: [ + CommonModule + ] +}) +export class ToObservableModule { +} diff --git a/core/app/core/src/lib/pipes/toObservable/toObservable.pipe.ts b/core/app/core/src/lib/pipes/toObservable/toObservable.pipe.ts new file mode 100644 index 0000000000..75a882773f --- /dev/null +++ b/core/app/core/src/lib/pipes/toObservable/toObservable.pipe.ts @@ -0,0 +1,37 @@ +/** + * SuiteCRM is a customer relationship management program developed by SalesAgility Ltd. + * Copyright (C) 2023 SalesAgility Ltd. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SALESAGILITY, SALESAGILITY DISCLAIMS THE + * WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * In accordance with Section 7(b) of the GNU Affero General Public License + * version 3, these Appropriate Legal Notices must retain the display of the + * "Supercharged by SuiteCRM" logo. If the display of the logos is not reasonably + * feasible for technical reasons, the Appropriate Legal Notices must display + * the words "Supercharged by SuiteCRM". + */ + +import { Pipe, PipeTransform } from '@angular/core'; +import { Observable, of } from 'rxjs'; + +@Pipe({ + name: 'toObservable' +}) +export class ToObservablePipe implements PipeTransform { + transform(value: any): Observable { + return of(value); + } +} diff --git a/core/app/core/src/lib/views/create/store/create-view/create-view.store.ts b/core/app/core/src/lib/views/create/store/create-view/create-view.store.ts index f27118f765..2f719043b9 100644 --- a/core/app/core/src/lib/views/create/store/create-view/create-view.store.ts +++ b/core/app/core/src/lib/views/create/store/create-view/create-view.store.ts @@ -45,6 +45,7 @@ import {MessageService} from '../../../../services/message/message.service'; import {Record, ViewMode} from 'common'; import {RecordStoreFactory} from '../../../../store/record/record.store.factory'; import {UserPreferenceStore} from '../../../../store/user-preference/user-preference.store'; +import {PanelLogicManager} from '../../../../components/panel-logic/panel-logic.manager'; @Injectable() export class CreateViewStore extends RecordViewStore { @@ -64,7 +65,8 @@ export class CreateViewStore extends RecordViewStore { protected statisticsBatch: StatisticsBatch, protected auth: AuthService, protected recordStoreFactory: RecordStoreFactory, - protected preferences: UserPreferenceStore + protected preferences: UserPreferenceStore, + protected panelLogicManager: PanelLogicManager ) { super( recordFetchGQL, @@ -80,7 +82,8 @@ export class CreateViewStore extends RecordViewStore { recordManager, statisticsBatch, recordStoreFactory, - preferences + preferences, + panelLogicManager ); } @@ -177,6 +180,7 @@ export class CreateViewStore extends RecordViewStore { tap((data: Record) => { data.id = ''; data.attributes.id = ''; + // eslint-disable-next-line camelcase,@typescript-eslint/camelcase data.attributes.date_entered = ''; this.recordManager.injectParamFields(this.params, data, this.getVardefs()); this.recordStore.setRecord(data); diff --git a/core/app/core/src/lib/views/record/adapters/actions.adapter.ts b/core/app/core/src/lib/views/record/adapters/actions.adapter.ts index e14c00d625..bf09b77950 100644 --- a/core/app/core/src/lib/views/record/adapters/actions.adapter.ts +++ b/core/app/core/src/lib/views/record/adapters/actions.adapter.ts @@ -95,6 +95,7 @@ export class RecordActionsAdapter extends BaseRecordActionsAdapter { - return combineLatest( - [this.metadata.recordViewMetadata$, this.store.stagingRecord$, this.language.vm$] - ).pipe( - map(([meta, record, languages]) => { - const panels = []; - const module = (record && record.module) || ''; - - this.fieldSubs.forEach(sub => sub.unsubscribe()); - - meta.panels.forEach(panelDefinition => { - const label = this.language.getFieldLabel(panelDefinition.key.toUpperCase(), module, languages); - const panel = {label, key: panelDefinition.key, rows: []} as Panel; - - const tabDef = meta.templateMeta.tabDefs[panelDefinition.key.toUpperCase()] ?? null; - if(tabDef) { - panel.meta = tabDef; - } - - panelDefinition.rows.forEach(rowDefinition => { - const row = {cols: []} as PanelRow; - rowDefinition.cols.forEach(cellDefinition => { - row.cols.push({...cellDefinition}); - }); - panel.rows.push(row); - }); - - panel.displayState = new BehaviorSubject(tabDef?.display ?? true); - panel.display$ = panel.displayState.asObservable(); - - panels.push(panel); - - if (tabDef?.displayLogic) { - Object.keys(tabDef.displayLogic).forEach((logicDefKey) => { - const logicDef = tabDef.displayLogic[logicDefKey]; - const logicType = logicDef.key; - - if(logicDef.params.fieldDependencies && (record && record.fields)) { - logicDef.params.fieldDependencies.forEach(fieldKey => { - const field = record.fields[fieldKey] || null; - if (!field) { - return; - } - - this.fieldSubs.push(field.valueChanges$.subscribe((value) => { - this.logicManager.runLogic(logicType, field, panel, record, this.store.getMode()); - - })); - }); - } - }); - } - }); - return panels; - }) - ); + return this.store.panels$; } getRecord(): Observable { diff --git a/core/app/core/src/lib/views/record/store/record-view/record-view.store.ts b/core/app/core/src/lib/views/record/store/record-view/record-view.store.ts index 69fd742fca..2f3da87d1b 100644 --- a/core/app/core/src/lib/views/record/store/record-view/record-view.store.ts +++ b/core/app/core/src/lib/views/record/store/record-view/record-view.store.ts @@ -24,6 +24,7 @@ * the words "Supercharged by SuiteCRM". */ +import {isEmpty} from 'lodash-es'; import {Injectable} from '@angular/core'; import {BehaviorSubject, combineLatest, Observable, of, Subscription} from 'rxjs'; import { @@ -37,7 +38,9 @@ import { SubPanelMeta, ViewContext, ViewFieldDefinition, - ViewMode + ViewMode, + Panel, + PanelRow, } from 'common'; import {catchError, distinctUntilChanged, finalize, map, take, tap} from 'rxjs/operators'; import {RecordViewData, RecordViewModel, RecordViewState} from './record-view.store.model'; @@ -65,6 +68,7 @@ import {Params} from '@angular/router'; import {StatisticsBatch} from '../../../../store/statistics/statistics-batch.service'; import {RecordStoreFactory} from '../../../../store/record/record.store.factory'; import {UserPreferenceStore} from '../../../../store/user-preference/user-preference.store'; +import {PanelLogicManager} from '../../../../components/panel-logic/panel-logic.manager'; const initialState: RecordViewState = { module: '', @@ -99,6 +103,8 @@ export class RecordViewStore extends ViewStore implements StateStore { subpanels$: Observable; viewContext$: Observable; subpanelReload$: Observable; + panels: Panel[] = []; + panels$: Observable; /** @@ -119,6 +125,8 @@ export class RecordViewStore extends ViewStore implements StateStore { protected subpanelReloadSubject = new BehaviorSubject({} as BooleanMap); protected subpanelReloadSub: Subscription[] = []; protected subs: Subscription[] = []; + protected fieldSubs: Subscription[] = []; + protected panelsSubject: BehaviorSubject = new BehaviorSubject(this.panels); constructor( protected recordFetchGQL: RecordFetchGQL, @@ -134,11 +142,14 @@ export class RecordViewStore extends ViewStore implements StateStore { protected recordManager: RecordManager, protected statisticsBatch: StatisticsBatch, protected recordStoreFactory: RecordStoreFactory, - protected preferences: UserPreferenceStore + protected preferences: UserPreferenceStore, + protected panelLogicManager: PanelLogicManager, ) { super(appStateStore, languageStore, navigationStore, moduleNavigation, metadataStore); + this.panels$ = this.panelsSubject.asObservable(); + this.recordStore = recordStoreFactory.create(this.getViewFieldsObservable()); this.record$ = this.recordStore.state$.pipe(distinctUntilChanged()); @@ -170,9 +181,8 @@ export class RecordViewStore extends ViewStore implements StateStore { this.subpanels$ = this.subpanelsState.asObservable(); - this.viewContext$ = this.record$.pipe(map(() => { - return this.getViewContext(); - })); + this.viewContext$ = this.record$.pipe(map(() => this.getViewContext())); + this.initPanels(); } get widgets(): boolean { @@ -293,6 +303,8 @@ export class RecordViewStore extends ViewStore implements StateStore { this.clearSubpanels(); this.subpanelsState.unsubscribe(); this.updateState(deepClone(initialState)); + this.subs = this.safeUnsubscription(this.subs); + this.fieldSubs = this.safeUnsubscription(this.fieldSubs); } /** @@ -522,6 +534,70 @@ export class RecordViewStore extends ViewStore implements StateStore { }); } + protected initPanels(): void { + const panelSub = combineLatest([ + this.metadataStore.recordViewMetadata$, + this.stagingRecord$, + this.languageStore.vm$, + ]).subscribe(([meta, record, languages]) => { + const panels = []; + const module = (record && record.module) || ''; + + this.safeUnsubscription(this.fieldSubs); + meta.panels.forEach(panelDefinition => { + const label = (panelDefinition.label) + ? panelDefinition.label.toUpperCase() + : this.languageStore.getFieldLabel(panelDefinition.key.toUpperCase(), module, languages); + const panel = { label, key: panelDefinition.key, rows: [] } as Panel; + + const tabDef = meta.templateMeta.tabDefs[panelDefinition.key.toUpperCase()] ?? null; + if (tabDef) { + panel.meta = tabDef; + } + + panelDefinition.rows.forEach(rowDefinition => { + const row = { cols: [] } as PanelRow; + rowDefinition.cols.forEach(cellDefinition => { + row.cols.push({ ...cellDefinition }); + }); + panel.rows.push(row); + }); + + panel.displayState = new BehaviorSubject(tabDef?.display ?? true); + panel.display$ = panel.displayState.asObservable(); + + panels.push(panel); + + if (isEmpty(record?.fields) || isEmpty(tabDef?.displayLogic)) { + return; + } + + Object.values(tabDef.displayLogic).forEach((logicDef) => { + if (isEmpty(logicDef?.params?.fieldDependencies)) { + return; + } + + logicDef.params.fieldDependencies.forEach(fieldKey => { + const field = record.fields[fieldKey] || null; + if (isEmpty(field)) { + return; + } + + this.fieldSubs.push( + field.valueChanges$.subscribe(() => { + this.panelLogicManager.runLogic(logicDef.key, field, panel, record, this.getMode()); + }), + ); + }); + }); + }); + this.panelsSubject.next(this.panels = panels); + return panels; + }); + + this.subs.push(panelSub); + } + protected clearSubpanels(): void { if (this.subpanels) { Object.keys(this.subpanels).forEach((key: string) => { @@ -602,8 +678,10 @@ export class RecordViewStore extends ViewStore implements StateStore { /** * Build ui user preference key - * @param storageKey + * + * @param {string} storageKey Storage Key * @protected + * @returns {string} Preference Key */ protected getPreferenceKey(storageKey: string): string { return 'recordview-' + storageKey; @@ -611,9 +689,10 @@ export class RecordViewStore extends ViewStore implements StateStore { /** * Save ui user preference - * @param module - * @param storageKey - * @param value + * + * @param {string} module Module + * @param {string} storageKey Storage Key + * @param {any} value Value * @protected */ protected savePreference(module: string, storageKey: string, value: any): void { @@ -622,9 +701,11 @@ export class RecordViewStore extends ViewStore implements StateStore { /** * Load ui user preference - * @param module - * @param storageKey + * + * @param {string} module Module + * @param {string} storageKey Storage Key * @protected + * @returns {any} User Preference */ protected loadPreference(module: string, storageKey: string): any { return this.preferences.getUi(module, this.getPreferenceKey(storageKey)); @@ -678,4 +759,16 @@ export class RecordViewStore extends ViewStore implements StateStore { }); } + private safeUnsubscription(subscriptionArray: Subscription[]): Subscription[] { + subscriptionArray.forEach(sub => { + if (sub.closed) { + return; + } + + sub.unsubscribe(); + }); + subscriptionArray = []; + + return subscriptionArray; + } } From a1bbaf0a229373dc9d4950dcbb9b1c98fa915787 Mon Sep 17 00:00:00 2001 From: "Moises E. Puyosa" Date: Fri, 10 Nov 2023 12:44:35 -0500 Subject: [PATCH 2/2] Fix #329 - Button Logic - Submit Required --- .../src/lib/components/button/button.model.ts | 2 + .../common/src/lib/metadata/metadata.model.ts | 1 + .../action-group-menu.component.ts | 19 +- .../components/button/button.component.html | 2 + .../lib/components/button/button.component.ts | 10 +- .../views/record/adapters/actions.adapter.ts | 177 ++++++++++++++++-- .../suite8/css/components/_button-danger.scss | 2 + .../suite8/css/components/_button-main.scss | 2 + .../css/components/_button-primary.scss | 2 + .../css/components/_button-secondary.scss | 2 + .../themes/suite8/css/components/_button.scss | 1 + 11 files changed, 193 insertions(+), 27 deletions(-) diff --git a/core/app/common/src/lib/components/button/button.model.ts b/core/app/common/src/lib/components/button/button.model.ts index f761d12666..b09d2efa01 100644 --- a/core/app/common/src/lib/components/button/button.model.ts +++ b/core/app/common/src/lib/components/button/button.model.ts @@ -23,6 +23,7 @@ * feasible for technical reasons, the Appropriate Legal Notices must display * the words "Supercharged by SuiteCRM". */ +import {Observable} from 'rxjs'; export declare type ButtonCallback = (...args) => void; @@ -37,6 +38,7 @@ export interface ButtonInterface { icon?: string; iconKlass?: string; labelModule?: string; + disabled$?: Observable; } export class Button implements ButtonInterface { diff --git a/core/app/common/src/lib/metadata/metadata.model.ts b/core/app/common/src/lib/metadata/metadata.model.ts index 4e1267f8ec..c0ba3bb0db 100644 --- a/core/app/common/src/lib/metadata/metadata.model.ts +++ b/core/app/common/src/lib/metadata/metadata.model.ts @@ -61,6 +61,7 @@ export interface PanelRow { export interface PanelCell extends ViewFieldDefinition { name?: string; + required_f_submit?: boolean; } export interface ViewFieldDefinitionMap { diff --git a/core/app/core/src/lib/components/action-group-menu/action-group-menu.component.ts b/core/app/core/src/lib/components/action-group-menu/action-group-menu.component.ts index f74f3a3e1e..8bd90c51df 100644 --- a/core/app/core/src/lib/components/action-group-menu/action-group-menu.component.ts +++ b/core/app/core/src/lib/components/action-group-menu/action-group-menu.component.ts @@ -52,7 +52,7 @@ export class ActionGroupMenuComponent implements OnInit { @Input() buttonGroupClass = ''; @Input() actionContext: ActionContext; @Input() config: ActionDataSource; - @Input() actionLimitConfig: string = 'recordview_actions_limits'; + @Input() actionLimitConfig = 'recordview_actions_limits'; configState = new BehaviorSubject({buttons: []}); config$ = this.configState.asObservable(); @@ -170,7 +170,7 @@ export class ActionGroupMenuComponent implements OnInit { this.triggerTemporaryLoading(); const callback = (): void => { this.config.runAction(action, this.actionContext); - } + }; this.initInlineConfirmation(action, callback); return; @@ -204,11 +204,16 @@ export class ActionGroupMenuComponent implements OnInit { Button.appendClasses(button, action.klass); } + if(action.disabled$){ + button.disabled$ = action.disabled$; + } + return button; } - protected triggerTemporaryLoading() { + protected triggerTemporaryLoading(): void { this.loading = true; + // eslint-disable-next-line radix const delay = parseInt(this.systemConfigStore.getUi('inline_confirmation_loading_delay')) ?? 200; setTimeout(() => { this.loading = false; @@ -221,8 +226,8 @@ export class ActionGroupMenuComponent implements OnInit { this.confirmationLabel = action?.params?.confirmationLabel ?? ''; this.confirmationDynamicLabel = action?.params?.confirmationDynamicLabel ?? ''; - this.inlineCancelButton = this.buildInlineCancelButton(cancelConfig) - this.inlineConfirmButton = this.buildInlineConfirmButton(confirmConfig, callback) + this.inlineCancelButton = this.buildInlineCancelButton(cancelConfig); + this.inlineConfirmButton = this.buildInlineConfirmButton(confirmConfig, callback); this.inlineConfirmationEnabled = true; } @@ -237,7 +242,7 @@ export class ActionGroupMenuComponent implements OnInit { button.onClick = (): void => { this.triggerTemporaryLoading(); this.resetInlineConfirmation(); - } + }; return button; } @@ -254,7 +259,7 @@ export class ActionGroupMenuComponent implements OnInit { this.triggerTemporaryLoading(); callback(); this.resetInlineConfirmation(); - } + }; return button; } diff --git a/core/app/core/src/lib/components/button/button.component.html b/core/app/core/src/lib/components/button/button.component.html index 6c3a80fd9f..58b8216e16 100644 --- a/core/app/core/src/lib/components/button/button.component.html +++ b/core/app/core/src/lib/components/button/button.component.html @@ -27,7 +27,9 @@ -->