/* * This file belongs to Hoist, an application development toolkit * developed by Extremely Heavy Industries (www.xh.io | info@xh.io) * * Copyright © 2026 Extremely Heavy Industries Inc. */ import {HoistModel, managed, TaskObserver, XH} from '@xh/hoist/core'; import {action, computed, makeObservable, observable} from '@xh/hoist/mobx'; import {omit} from 'lodash'; import {RoleModel} from '../RoleModel'; import {HoistRole} from '../Types'; import {RoleFormModel} from './form/RoleFormModel'; export class RoleEditorModel extends HoistModel { override telemetryPrefix = 'xh.client.admin.roles'; readonly roleModel: RoleModel; readonly savingTask = TaskObserver.trackLast({message: 'Saving Role'}); readonly deletingTask = TaskObserver.trackLast({message: 'Deleting Role'}); @managed roleFormModel: RoleFormModel; @observable isOpen = false; @observable role?: HoistRole; private resolve: (role?: HoistRole) => void; @computed get saveDisabled(): boolean { return !this.roleFormModel.isDirty || !this.roleFormModel.isValid; } constructor(roleModel: RoleModel) { super(); makeObservable(this); this.roleModel = roleModel; this.roleFormModel = new RoleFormModel(roleModel); } async createAsync(roleSpec?: HoistRole): Promise { return this.openAsync(roleSpec); } async editAsync(role: HoistRole): Promise { return this.openAsync(role, true); } @action async saveAsync(): Promise { const isValid = this.roleFormModel.validateAsync(); if (!isValid) return; const method = this.role ? 'update' : 'create'; return this.runner() .span(method) .run(async ctx => { const {data} = await XH.postJson( { body: this.roleFormModel.getData(), url: `roleAdmin/${method}` }, ctx ).linkTo(this.savingTask); this.resolve(data); this.close(); }) .catchDefault(); } async deleteAsync(): Promise { return this.roleModel .deleteAsync(this.role) .linkTo(this.deletingTask) .thenAction(successful => successful && this.close()) .catchDefault(); } cancel() { if (!this.roleFormModel.isDirty) { this.doCancel(); } else { XH.confirm({ message: 'You have unsaved changes. Are you sure you want to proceed?', cancelProps: { text: 'Keep editing' }, confirmProps: { text: 'Discard Changes', intent: 'danger', outlined: true }, onConfirm: () => this.doCancel() }); } } // ------------------------------- // Implementation // ------------------------------- @action private openAsync(roleSpec?: HoistRole, editExisting = false): Promise { this.isOpen = true; this.role = editExisting ? roleSpec : undefined; this.roleFormModel.init( this.roleModel.allRoles, editExisting ? roleSpec : omit(roleSpec, 'name') ); return new Promise(resolve => (this.resolve = resolve)); } private doCancel() { this.resolve(); this.close(); } @action private close() { this.isOpen = false; } }