@cccteam/ccc-lib 0.0.14 → 0.0.16
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.
- package/README.md +38 -13
- package/fesm2022/cccteam-ccc-lib-src-auth-authentication-guard.mjs.map +1 -1
- package/fesm2022/cccteam-ccc-lib-src-auth-authorization-guard.mjs.map +1 -1
- package/fesm2022/cccteam-ccc-lib-src-auth-forms.mjs +15 -49
- package/fesm2022/cccteam-ccc-lib-src-auth-forms.mjs.map +1 -1
- package/fesm2022/cccteam-ccc-lib-src-auth-has-permission.mjs +4 -4
- package/fesm2022/cccteam-ccc-lib-src-auth-has-permission.mjs.map +1 -1
- package/fesm2022/cccteam-ccc-lib-src-auth-service.mjs +16 -22
- package/fesm2022/cccteam-ccc-lib-src-auth-service.mjs.map +1 -1
- package/fesm2022/cccteam-ccc-lib-src-ccc-camel-case-to-title.mjs +33 -0
- package/fesm2022/cccteam-ccc-lib-src-ccc-camel-case-to-title.mjs.map +1 -0
- package/fesm2022/cccteam-ccc-lib-src-ccc-grid.mjs +256 -0
- package/fesm2022/cccteam-ccc-lib-src-ccc-grid.mjs.map +1 -0
- package/fesm2022/cccteam-ccc-lib-src-ccc-resource.mjs +3129 -0
- package/fesm2022/cccteam-ccc-lib-src-ccc-resource.mjs.map +1 -0
- package/fesm2022/cccteam-ccc-lib-src-forms.mjs +79 -0
- package/fesm2022/cccteam-ccc-lib-src-forms.mjs.map +1 -0
- package/fesm2022/cccteam-ccc-lib-src-internal-types.mjs +6 -0
- package/fesm2022/cccteam-ccc-lib-src-internal-types.mjs.map +1 -0
- package/fesm2022/cccteam-ccc-lib-src-types.mjs +406 -112
- package/fesm2022/cccteam-ccc-lib-src-types.mjs.map +1 -1
- package/fesm2022/cccteam-ccc-lib-src-ui-alert.mjs +3 -3
- package/fesm2022/cccteam-ccc-lib-src-ui-alert.mjs.map +1 -1
- package/fesm2022/cccteam-ccc-lib-src-ui-core-service.mjs +7 -7
- package/fesm2022/cccteam-ccc-lib-src-ui-core-service.mjs.map +1 -1
- package/fesm2022/cccteam-ccc-lib-src-ui-idle-service.mjs +157 -0
- package/fesm2022/cccteam-ccc-lib-src-ui-idle-service.mjs.map +1 -0
- package/fesm2022/cccteam-ccc-lib-src-ui-interceptor.mjs +4 -4
- package/fesm2022/cccteam-ccc-lib-src-ui-interceptor.mjs.map +1 -1
- package/fesm2022/cccteam-ccc-lib-src-ui-notification-service.mjs +5 -5
- package/fesm2022/cccteam-ccc-lib-src-ui-notification-service.mjs.map +1 -1
- package/fesm2022/cccteam-ccc-lib-src-ui-sidenav.mjs +4 -4
- package/fesm2022/cccteam-ccc-lib-src-ui-sidenav.mjs.map +1 -1
- package/fesm2022/cccteam-ccc-lib-src-util-request-options.mjs.map +1 -1
- package/fesm2022/cccteam-ccc-lib.mjs +4434 -12
- package/fesm2022/cccteam-ccc-lib.mjs.map +1 -1
- package/package.json +44 -18
- package/{src/auth-forms/index.d.ts → types/cccteam-ccc-lib-src-auth-forms.d.ts} +1 -18
- package/{src/auth-service/index.d.ts → types/cccteam-ccc-lib-src-auth-service.d.ts} +3 -1
- package/types/cccteam-ccc-lib-src-ccc-camel-case-to-title.d.ts +10 -0
- package/types/cccteam-ccc-lib-src-ccc-grid.d.ts +35 -0
- package/types/cccteam-ccc-lib-src-ccc-resource.d.ts +674 -0
- package/types/cccteam-ccc-lib-src-forms.d.ts +27 -0
- package/types/cccteam-ccc-lib-src-internal-types.d.ts +1 -0
- package/types/cccteam-ccc-lib-src-types.d.ts +934 -0
- package/types/cccteam-ccc-lib-src-ui-idle-service.d.ts +49 -0
- package/types/cccteam-ccc-lib.d.ts +1877 -0
- package/index.d.ts +0 -12
- package/src/types/index.d.ts +0 -133
- /package/{src/auth-authentication-guard/index.d.ts → types/cccteam-ccc-lib-src-auth-authentication-guard.d.ts} +0 -0
- /package/{src/auth-authorization-guard/index.d.ts → types/cccteam-ccc-lib-src-auth-authorization-guard.d.ts} +0 -0
- /package/{src/auth-has-permission/index.d.ts → types/cccteam-ccc-lib-src-auth-has-permission.d.ts} +0 -0
- /package/{src/ui-alert/index.d.ts → types/cccteam-ccc-lib-src-ui-alert.d.ts} +0 -0
- /package/{src/ui-core-service/index.d.ts → types/cccteam-ccc-lib-src-ui-core-service.d.ts} +0 -0
- /package/{src/ui-interceptor/index.d.ts → types/cccteam-ccc-lib-src-ui-interceptor.d.ts} +0 -0
- /package/{src/ui-notification-service/index.d.ts → types/cccteam-ccc-lib-src-ui-notification-service.d.ts} +0 -0
- /package/{src/ui-sidenav/index.d.ts → types/cccteam-ccc-lib-src-ui-sidenav.d.ts} +0 -0
- /package/{src/util-request-options/index.d.ts → types/cccteam-ccc-lib-src-util-request-options.d.ts} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cccteam-ccc-lib-src-types.mjs","sources":["../../../projects/ccc-lib/src/types/auth.actions.ts","../../../projects/ccc-lib/src/types/core.actions.ts","../../../projects/ccc-lib/src/types/notification-message.ts","../../../projects/ccc-lib/src/types/permissions.ts","../../../projects/ccc-lib/src/types/tokens.ts","../../../projects/ccc-lib/src/types/cccteam-ccc-lib-src-types.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-namespace */\n// no-namespace rule is disabled because action hygiene prevents import pollution\n\nimport { CreateNotificationMessage } from './notification-message';\nexport namespace AuthenticationGuardAction {\n export class SetRedirectUrl {\n static readonly type = '[AuthenticationGuard] Set Redirect Url And Navigate To Login Page';\n constructor(public redirectUrl: string) {}\n }\n\n export class CheckUserSession {\n static readonly type = '[AuthenticationGuard] Check User Session';\n }\n}\n\nexport namespace LoginAction {\n export class Logout {\n static readonly type = '[Login] Auto Logout';\n }\n\n export class SetRedirectUrl {\n static readonly type = '[Login] Set Redirect Url';\n constructor(public redirectUrl: string) {}\n }\n\n export class PublishError {\n static readonly type = '[Login] Publish Error';\n constructor(public message: CreateNotificationMessage) {}\n }\n}\n\nexport namespace AppAction {\n export class CheckUserSession {\n static readonly type = '[App] Check User Session';\n }\n\n export class SetRedirectUrl {\n static readonly type = '[App] Set Redirect Url';\n constructor(public redirectUrl: string) {}\n }\n\n export class SetNavIdentifier {\n static readonly type = '[App] Set Nav Identifier';\n constructor(public identifier: string) {}\n }\n}\n","/* eslint-disable @typescript-eslint/no-namespace */\n// no-namespace rule is disabled because action hygiene prevents import pollution\n\nimport { CreateNotificationMessage } from './notification-message';\n\nexport namespace ApiInterceptorAction {\n export class BeginActivity {\n static readonly type = '[ApiInterceptor] Add Loading Activity';\n constructor(public process: string) {}\n }\n export class EndActivity {\n static readonly type = '[ApiInterceptor] Remove Loading Activity';\n constructor(public process: string) {}\n }\n export class PublishError {\n static readonly type = '[ApiInterceptor] Publish Error';\n constructor(public message: CreateNotificationMessage) {}\n }\n export class SetRedirectUrl {\n static readonly type = '[ApiInterceptor] Set Redirect Url';\n constructor(public redirectUrl: string) {}\n }\n}\n\nexport namespace HeaderAction {\n export class ToggleSidenav {\n static readonly type = '[Header] Toggle Sidenav';\n }\n\n export class Logout {\n static readonly type = '[Header] User Logout';\n }\n}\n","export enum AlertLevel {\n ERROR = 'warn',\n INFO = 'accent',\n SUCCESS = 'success',\n}\n\nexport interface CreateNotificationMessage {\n duration?: number;\n message: string;\n link: string;\n level: AlertLevel;\n}\n\nexport interface NotificationMessage {\n id: number;\n duration?: number;\n message: string;\n link: string;\n level: AlertLevel;\n}\n","type Brand<K, T> = K & { __brand: T };\n\nexport type Permission = Brand<string, 'Permission'>;\nexport type Resource = Brand<string, 'Resource'>;\nexport type Domain = Brand<string, 'Domain'>;\nexport type FieldName = Brand<string, 'FieldName'>;\nexport type Method = Brand<string, 'Method'>;\nexport type DomainPermissions = Record<Domain, Record<Resource, Record<Permission, Permissions>>>;\n\nexport interface PermissionScope {\n resource: Resource;\n permission: Permission;\n domain: Domain;\n}\n\nexport const ReadPermission = 'Read' as Permission;\nexport const UpdatePermission = 'Update' as Permission;\n","import { InjectionToken } from '@angular/core';\nimport { Domain, Permission, Resource } from './permissions';\n\nexport const BASE_URL = new InjectionToken<string>('BASE_URL');\nexport const API_URL = new InjectionToken<string>('API_URL');\nexport const PERMISSION_REQUIRED = new InjectionToken<(resource: Resource, permission: Permission) => boolean>(\n 'PERMISSION_REQUIRED',\n);\n\nexport const AVAILABLE_PERMISSIONS = new InjectionToken<{\n Create: Permission;\n Delete: Permission;\n List: Permission;\n Read: Permission;\n Update: Permission;\n}>('AVAILABLE_PERMISSIONS');\nexport const AVAILABLE_DOMAINS = new InjectionToken<Record<string, Domain>[]>('AVAILABLE_DOMAINS');\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;AAAA;AACA;AAGM,IAAW;AAAjB,CAAA,UAAiB,yBAAyB,EAAA;AACxC,IAAA,MAAa,cAAc,CAAA;AAEN,QAAA,WAAA;AADnB,QAAA,OAAgB,IAAI,GAAG,mEAAmE;AAC1F,QAAA,WAAA,CAAmB,WAAmB,EAAA;YAAnB,IAAW,CAAA,WAAA,GAAX,WAAW;;;AAFnB,IAAA,yBAAA,CAAA,cAAc,iBAG1B;AAED,IAAA,MAAa,gBAAgB,CAAA;AAC3B,QAAA,OAAgB,IAAI,GAAG,0CAA0C;;AADtD,IAAA,yBAAA,CAAA,gBAAgB,mBAE5B;AACH,CAAC,EATgB,yBAAyB,KAAzB,yBAAyB,GASzC,EAAA,CAAA,CAAA;AAEK,IAAW;AAAjB,CAAA,UAAiB,WAAW,EAAA;AAC1B,IAAA,MAAa,MAAM,CAAA;AACjB,QAAA,OAAgB,IAAI,GAAG,qBAAqB;;AADjC,IAAA,WAAA,CAAA,MAAM,SAElB;AAED,IAAA,MAAa,cAAc,CAAA;AAEN,QAAA,WAAA;AADnB,QAAA,OAAgB,IAAI,GAAG,0BAA0B;AACjD,QAAA,WAAA,CAAmB,WAAmB,EAAA;YAAnB,IAAW,CAAA,WAAA,GAAX,WAAW;;;AAFnB,IAAA,WAAA,CAAA,cAAc,iBAG1B;AAED,IAAA,MAAa,YAAY,CAAA;AAEJ,QAAA,OAAA;AADnB,QAAA,OAAgB,IAAI,GAAG,uBAAuB;AAC9C,QAAA,WAAA,CAAmB,OAAkC,EAAA;YAAlC,IAAO,CAAA,OAAA,GAAP,OAAO;;;AAFf,IAAA,WAAA,CAAA,YAAY,eAGxB;AACH,CAAC,EAdgB,WAAW,KAAX,WAAW,GAc3B,EAAA,CAAA,CAAA;AAEK,IAAW;AAAjB,CAAA,UAAiB,SAAS,EAAA;AACxB,IAAA,MAAa,gBAAgB,CAAA;AAC3B,QAAA,OAAgB,IAAI,GAAG,0BAA0B;;AADtC,IAAA,SAAA,CAAA,gBAAgB,mBAE5B;AAED,IAAA,MAAa,cAAc,CAAA;AAEN,QAAA,WAAA;AADnB,QAAA,OAAgB,IAAI,GAAG,wBAAwB;AAC/C,QAAA,WAAA,CAAmB,WAAmB,EAAA;YAAnB,IAAW,CAAA,WAAA,GAAX,WAAW;;;AAFnB,IAAA,SAAA,CAAA,cAAc,iBAG1B;AAED,IAAA,MAAa,gBAAgB,CAAA;AAER,QAAA,UAAA;AADnB,QAAA,OAAgB,IAAI,GAAG,0BAA0B;AACjD,QAAA,WAAA,CAAmB,UAAkB,EAAA;YAAlB,IAAU,CAAA,UAAA,GAAV,UAAU;;;AAFlB,IAAA,SAAA,CAAA,gBAAgB,mBAG5B;AACH,CAAC,EAdgB,SAAS,KAAT,SAAS,GAczB,EAAA,CAAA,CAAA;;AC7CD;AACA;AAIM,IAAW;AAAjB,CAAA,UAAiB,oBAAoB,EAAA;AACnC,IAAA,MAAa,aAAa,CAAA;AAEL,QAAA,OAAA;AADnB,QAAA,OAAgB,IAAI,GAAG,uCAAuC;AAC9D,QAAA,WAAA,CAAmB,OAAe,EAAA;YAAf,IAAO,CAAA,OAAA,GAAP,OAAO;;;AAFf,IAAA,oBAAA,CAAA,aAAa,gBAGzB;AACD,IAAA,MAAa,WAAW,CAAA;AAEH,QAAA,OAAA;AADnB,QAAA,OAAgB,IAAI,GAAG,0CAA0C;AACjE,QAAA,WAAA,CAAmB,OAAe,EAAA;YAAf,IAAO,CAAA,OAAA,GAAP,OAAO;;;AAFf,IAAA,oBAAA,CAAA,WAAW,cAGvB;AACD,IAAA,MAAa,YAAY,CAAA;AAEJ,QAAA,OAAA;AADnB,QAAA,OAAgB,IAAI,GAAG,gCAAgC;AACvD,QAAA,WAAA,CAAmB,OAAkC,EAAA;YAAlC,IAAO,CAAA,OAAA,GAAP,OAAO;;;AAFf,IAAA,oBAAA,CAAA,YAAY,eAGxB;AACD,IAAA,MAAa,cAAc,CAAA;AAEN,QAAA,WAAA;AADnB,QAAA,OAAgB,IAAI,GAAG,mCAAmC;AAC1D,QAAA,WAAA,CAAmB,WAAmB,EAAA;YAAnB,IAAW,CAAA,WAAA,GAAX,WAAW;;;AAFnB,IAAA,oBAAA,CAAA,cAAc,iBAG1B;AACH,CAAC,EAjBgB,oBAAoB,KAApB,oBAAoB,GAiBpC,EAAA,CAAA,CAAA;AAEK,IAAW;AAAjB,CAAA,UAAiB,YAAY,EAAA;AAC3B,IAAA,MAAa,aAAa,CAAA;AACxB,QAAA,OAAgB,IAAI,GAAG,yBAAyB;;AADrC,IAAA,YAAA,CAAA,aAAa,gBAEzB;AAED,IAAA,MAAa,MAAM,CAAA;AACjB,QAAA,OAAgB,IAAI,GAAG,sBAAsB;;AADlC,IAAA,YAAA,CAAA,MAAM,SAElB;AACH,CAAC,EARgB,YAAY,KAAZ,YAAY,GAQ5B,EAAA,CAAA,CAAA;;IChCW;AAAZ,CAAA,UAAY,UAAU,EAAA;AACpB,IAAA,UAAA,CAAA,OAAA,CAAA,GAAA,MAAc;AACd,IAAA,UAAA,CAAA,MAAA,CAAA,GAAA,QAAe;AACf,IAAA,UAAA,CAAA,SAAA,CAAA,GAAA,SAAmB;AACrB,CAAC,EAJW,UAAU,KAAV,UAAU,GAIrB,EAAA,CAAA,CAAA;;ACWM,MAAM,cAAc,GAAG;AACvB,MAAM,gBAAgB,GAAG;;MCbnB,QAAQ,GAAG,IAAI,cAAc,CAAS,UAAU;MAChD,OAAO,GAAG,IAAI,cAAc,CAAS,SAAS;MAC9C,mBAAmB,GAAG,IAAI,cAAc,CACnD,qBAAqB;MAGV,qBAAqB,GAAG,IAAI,cAAc,CAMpD,uBAAuB;MACb,iBAAiB,GAAG,IAAI,cAAc,CAA2B,mBAAmB;;AChBjG;;AAEG;;;;"}
|
|
1
|
+
{"version":3,"file":"cccteam-ccc-lib-src-types.mjs","sources":["../../../projects/ccc-lib/src/types/resource-types.ts","../../../projects/ccc-lib/src/types/configs.ts","../../../projects/ccc-lib/src/types/notification-message.ts","../../../projects/ccc-lib/src/types/permissions.ts","../../../projects/ccc-lib/src/types/resource-meta.ts","../../../projects/ccc-lib/src/types/tokens.ts","../../../projects/ccc-lib/src/types/validators.ts","../../../projects/ccc-lib/src/types/cccteam-ccc-lib-src-types.ts"],"sourcesContent":["// Shared types and constants used across the ccc-resource module\n// This file exists to break circular dependencies between types and ccc-resource\n\nexport const defaultEmptyFieldValue = '-';\n\nexport type NullBoolean = null | true | false;\n\nexport type ConcatFn = 'space-concat' | 'hyphen-concat' | 'space-hyphen-concat' | 'hyphen-space-concat';\n","import { TooltipPosition } from '@angular/material/tooltip';\nimport { FieldName, Method, Resource } from './permissions';\nimport { ConcatFn, defaultEmptyFieldValue, NullBoolean } from './resource-types';\nimport { ResourceValidatorFn } from './validators';\n\nexport interface FieldPointer {\n field: FieldName;\n}\n\nexport interface MenuItem {\n label: string;\n route?: string[];\n children?: MenuItem[];\n}\n\nexport interface RouteResourceData {\n config: RootConfig;\n}\n\nexport type DataType = string | number | number[] | string[] | boolean | undefined | Date;\nexport type RecordData = Record<string, DataType | null>;\n\nexport type RPCDataType = string | number | string[] | number[] | boolean | Date;\nexport type RPCRecordData = Record<string, RPCDataType>;\nexport type RpcMethod = Record<string, DataType>;\n\nexport type ParentResourceConfig = ListViewConfig | ViewConfig | ArrayConfig;\nexport type ChildResourceConfig = ListViewConfig | ViewConfig | ComponentConfig | ArrayConfig;\n\nexport type ActionType = 'function' | 'link';\n\nexport type ListConcatFn =\n | 'space-concat'\n | 'hyphen-concat'\n | 'space-hyphen-concat'\n | 'hyphen-space-concat'\n | 'no-space-concat';\nexport type ConfigType = ChildResourceConfig;\nexport type FormatType = 'simpleSlashDateFormat';\nexport type RPCPlacement = 'inline' | 'end';\n\nexport type ColumnConfig = SingleColumnConfig | MultiColumnConfig;\n\nexport interface ActionButtonConfig {\n label: string;\n icon: string;\n action?: (resource: { id: string }) => void;\n viewRoute?: string;\n actionType?: ActionType;\n color?: string;\n disabledLabel?: string;\n}\nexport interface ActionButtonConfigOptions {\n label: string;\n icon: string;\n action?: (resource: { id: string }) => void;\n viewRoute?: string;\n actionType?: ActionType;\n color?: string;\n disabledLabel?: string;\n}\n\nexport function actionButtonConfig(config: ActionButtonConfigOptions): ActionButtonConfig {\n return {\n ...actionButtonConfigDefaults,\n ...config,\n } satisfies ActionButtonConfig;\n}\n\nexport const actionButtonConfigDefaults = {\n label: '',\n icon: '',\n actionType: 'function' as ActionType,\n color: '',\n disabledLabel: '',\n} satisfies ActionButtonConfig;\n\nexport interface SingleColumnConfig {\n id: FieldName;\n header?: string;\n width?: number;\n resizable?: boolean;\n /* eslint-disable @typescript-eslint/no-explicit-any */\n valueGetter?: (data: any) => string;\n valueFormatter?: (data: any) => string;\n tooltipPosition?: TooltipPosition;\n viewRoute?: Resource;\n buttonConfig?: ActionButtonConfig;\n actionType?: ActionType;\n formatType?: FormatType | string;\n hidden?: boolean;\n emptyDataValue?: DataType;\n filterable?: boolean;\n hideHeader?: boolean;\n}\nexport interface SingleColumnConfigOptions {\n id: FieldName;\n header?: string;\n width?: number;\n resizable?: boolean;\n /* eslint-disable @typescript-eslint/no-explicit-any */\n valueGetter?: (data: any) => string;\n valueFormatter?: (data: any) => string;\n tooltipPosition?: TooltipPosition;\n viewRoute?: Resource;\n buttonConfig?: ActionButtonConfig;\n actionType?: ActionType;\n formatType?: FormatType | string;\n hidden?: boolean;\n emptyDataValue?: DataType;\n filterable?: boolean;\n hideHeader?: boolean;\n}\n\nexport function singleColumnConfig(config: SingleColumnConfigOptions): SingleColumnConfig {\n return {\n ...singleColumnConfigDefaults,\n ...config,\n } satisfies SingleColumnConfig;\n}\n\nexport const singleColumnConfigDefaults = {\n id: '' as FieldName,\n header: '',\n resizable: true,\n actionType: 'function' as ActionType,\n hidden: false,\n filterable: true,\n hideHeader: false,\n} satisfies SingleColumnConfig;\n\nexport interface MultiColumnConfig extends SingleColumnConfig {\n // todo: additionalIds name is not clear. the id provided is fetched from a different resource, such as a typeId\n additionalIds: AdditionalResourceConfig[];\n concatFn: ListConcatFn;\n}\nexport interface MultiColumnConfigOptions extends SingleColumnConfigOptions {\n additionalIds: AdditionalResourceConfig[];\n concatFn: ListConcatFn;\n}\n\nexport function multiColumnConfig(config: MultiColumnConfigOptions): MultiColumnConfig {\n return {\n ...multiColumnConfigDefaults,\n ...config,\n } satisfies MultiColumnConfig;\n}\n\nexport const multiColumnConfigDefaults = {\n ...singleColumnConfigDefaults,\n additionalIds: [] as AdditionalResourceConfig[],\n concatFn: 'hyphen-concat' as ListConcatFn,\n} satisfies MultiColumnConfig;\n\nexport interface AdditionalResourceConfig {\n resource?: Resource;\n id: FieldName;\n field?: FieldName;\n hidden?: boolean;\n}\nexport interface AdditionalResourceConfigOptions {\n id: FieldName;\n resource?: Resource;\n field?: FieldName;\n hidden?: boolean;\n}\n\nexport function additionalResourceConfig(config: AdditionalResourceConfigOptions): AdditionalResourceConfig {\n return {\n ...additionalResourceConfigDefaults,\n ...config,\n } satisfies AdditionalResourceConfig;\n}\n\nexport const additionalResourceConfigDefaults = {\n id: '' as FieldName,\n resource: '' as Resource,\n field: '' as FieldName,\n hidden: false,\n} satisfies AdditionalResourceConfig;\n\nexport interface FieldSort {\n field: FieldName;\n direction: 'asc' | 'desc';\n}\nexport interface FieldSortOptions {\n field: FieldName;\n direction?: 'asc' | 'desc';\n}\n\nexport function fieldSort(config: FieldSortOptions): FieldSort {\n return {\n ...fieldSortDefaults,\n ...config,\n } satisfies FieldSort;\n}\n\nexport const fieldSortDefaults = {\n field: '' as FieldName,\n direction: 'asc' as 'asc' | 'desc',\n} satisfies FieldSort;\n\nexport interface EnumeratedConfigOptions {\n // primaryResource comes from the metadata\n overrideResource?: Resource;\n /* A function to filter the list of enumerated options.\n * The `parentResource` argument contains the data of the resource that this enumerated field is part of.\n * It will be an object with the current form values, which can be empty during resource creation.\n */\n /* eslint-disable @typescript-eslint/no-explicit-any */\n filter?: (resource: any) => string;\n /**\n * Set disableCacheForFilterPii to `true` to promote the GET to a POST when PII is used in the filter\n * POST requests cannot be cached\n */\n disableCacheForFilterPii?: boolean;\n /**\n * Specifies which resource data to pass to the filter function:\n * - 'rootResource': Pass in the root resource data\n * - 'parentResource': Pass in the parent resource data\n * @default 'parentResource'\n */\n filterType?: FilterType;\n sorts?: FieldSort[];\n listDisplay?: FieldName[];\n viewDisplay: FieldName[];\n viewConcatFn?: ConcatFn;\n listConcatFn?: ConcatFn;\n viewDetails?: boolean;\n searchable?: boolean;\n}\n\ntype FilterType = 'parentResource' | 'rootResource';\nexport interface EnumeratedConfig {\n overrideResource: Resource;\n filter: (resource: any) => string;\n disableCacheForFilterPii: boolean;\n filterType: FilterType;\n sorts: FieldSort[];\n listDisplay: FieldName[];\n viewDisplay: FieldName[];\n viewConcatFn: ConcatFn;\n listConcatFn: ConcatFn;\n viewDetails: boolean;\n searchable: boolean;\n}\nexport function enumeratedConfig(config: EnumeratedConfigOptions): EnumeratedConfig {\n return {\n ...enumeratedConfigDefaults,\n ...config,\n } satisfies EnumeratedConfig;\n}\nexport const enumeratedConfigDefaults = {\n overrideResource: '' as Resource,\n filter: (): string => '',\n disableCacheForFilterPii: false,\n filterType: 'parentResource' as FilterType,\n sorts: [] as FieldSort[],\n listDisplay: [] as FieldName[],\n viewDisplay: [] as FieldName[],\n viewConcatFn: 'hyphen-concat' as ConcatFn,\n listConcatFn: 'hyphen-concat' as ConcatFn,\n viewDetails: false,\n searchable: false,\n};\n\nexport type FieldDefault = ForeignKeyDefault | StaticDefault | null;\n\nexport interface NullBooleanConfigOptions {\n displayValues?: Record<'null' | 'true' | 'false', { label: string; value: NullBoolean }>;\n}\nexport interface NullBooleanConfig {\n /** This property maps the three possible values for this\n * nullboolean field with the display values users will see\n * on the screen for each\n */\n displayValues: Record<'null' | 'true' | 'false', { label: string; value: NullBoolean }>;\n\n /** TODO: In FUTURE PHASES once field change history is implemented\n * When this field is first displayed on screen, set the\n * value to null based on the value present in it.\n * Useful if the database doesn't have support nulling but you want\n * users to make a conscious selection, but the database\n * will either contain a true or false. Will need to check the\n * 'last edited' on the field to ensure that we don't repeatedly spam\n * users with this though\n */\n // nullOnEdit: {\n // nullIfTrue: boolean;\n // nullIfFalse: boolean;\n // };\n}\nexport function nullBooleanConfig(config: NullBooleanConfigOptions): NullBooleanConfig {\n return {\n ...nullBooleanConfigDefaults,\n ...config,\n } satisfies NullBooleanConfig;\n}\nconst defaultBooleanDisplay = Object.freeze({\n null: {\n label: defaultEmptyFieldValue,\n value: null,\n },\n true: {\n label: 'Yes',\n value: true,\n },\n false: {\n label: 'No',\n value: false,\n },\n});\n\nexport const nullBooleanConfigDefaults = {\n displayValues: defaultBooleanDisplay,\n};\n\nexport interface ForeignKeyDefaultOptions {\n parentId: FieldName;\n}\nexport interface ForeignKeyDefault {\n type: 'foreignKey';\n parentId: FieldName;\n}\nexport function foreignKeyDefault(config: ForeignKeyDefaultOptions): ForeignKeyDefault {\n return {\n ...foreignKeyDefaultDefaults,\n ...config,\n } satisfies ForeignKeyDefault;\n}\nexport const foreignKeyDefaultDefaults = {\n type: 'foreignKey',\n parentId: '' as FieldName,\n} satisfies ForeignKeyDefault;\n\nexport interface StaticDefault {\n type: 'static';\n value: string | boolean;\n}\nexport interface staticDefaultOptions {\n value: string | boolean;\n}\nexport function staticDefault(config: staticDefaultOptions): StaticDefault {\n return {\n ...staticDefaultDefaults,\n ...config,\n } satisfies StaticDefault;\n}\nexport const staticDefaultDefaults = {\n type: 'static',\n value: '',\n} satisfies StaticDefault;\n\nexport type Affix = string | remoteData | parentData;\n\ninterface remoteData {\n resource: Resource;\n id: FieldName;\n field: FieldName;\n}\n\ninterface parentData {\n field: FieldName;\n}\n\nexport type ConfigElement = FieldElement | SectionElement | ComputedDisplayFieldElement | PaddingElement;\n\nexport type ColSize = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;\n\nexport interface ComputedDisplayFieldElementOptions {\n label?: string;\n class?: string;\n cols?: ColSize;\n calculatedValue?: (data: any) => string;\n shouldRender?: ((data: any) => boolean) | boolean;\n}\nexport interface ComputedDisplayFieldElement {\n type: 'computedDisplayField';\n label: string;\n class: string;\n cols: ColSize;\n calculatedValue: (data: any) => string;\n shouldRender: ((data: any) => boolean) | boolean;\n}\nexport function computedDisplayField(config: ComputedDisplayFieldElementOptions): ComputedDisplayFieldElement {\n return {\n ...computedDisplayFieldElementDefaults,\n ...config,\n } satisfies ComputedDisplayFieldElement;\n}\nexport const computedDisplayFieldElementDefaults = {\n type: 'computedDisplayField',\n label: '',\n class: '',\n cols: 6,\n calculatedValue: (): string => '',\n shouldRender: true,\n} satisfies ComputedDisplayFieldElement;\n\nexport interface PaddingElementOptions {\n cols?: ColSize;\n shouldRender?: ((data: any) => boolean) | boolean;\n}\nexport interface PaddingElement {\n type: 'padding';\n cols: ColSize;\n /** Determines whether the padding is shown\n */\n shouldRender: ((data: any) => boolean) | boolean;\n}\nexport function padding(config?: PaddingElementOptions): PaddingElement {\n return {\n ...paddingElementDefaults,\n ...config,\n } satisfies PaddingElement;\n}\nexport const paddingElementDefaults = {\n type: 'padding',\n cols: 12,\n shouldRender: true,\n} satisfies PaddingElement;\n\nexport interface SectionElementOptions {\n label?: string;\n class?: string;\n cols?: ColSize;\n shouldRender?: ((data: any) => boolean) | boolean;\n nullAllChildrenIfConditionallyHidden?: boolean;\n children?: ConfigElement[];\n}\nexport interface SectionElement {\n type: 'section';\n label: string;\n class: string;\n cols: ColSize;\n /**\n * shouldRender is used to determine if the section should be\n * displayed to users.\n * When assigning shouldRender a function, the first argument\n * is the current state of the resource being displayed\n * Hides the layout AND all of its children\n */\n shouldRender: ((data: any) => boolean) | boolean;\n /** If shouldRender is NOT a function, this property does nothing\n * If shouldRender is a function, this property\n * sets children's values to null if shouldRender hides it (returns false)\n * within the resource-layout.component\n */\n nullAllChildrenIfConditionallyHidden: boolean;\n children: ConfigElement[];\n}\nexport function section(config: SectionElementOptions): SectionElement {\n return {\n ...sectionElementDefaults,\n ...config,\n } satisfies SectionElement;\n}\nexport const sectionElementDefaults = {\n type: 'section',\n label: '',\n class: '',\n cols: 12,\n shouldRender: true,\n nullAllChildrenIfConditionallyHidden: false,\n children: [],\n} satisfies SectionElement;\n\nexport interface FieldElementOptions {\n name: FieldName;\n label?: string;\n cols?: ColSize;\n class?: string;\n enumeratedConfig?: EnumeratedConfig;\n default?: FieldDefault;\n nullBooleanConfig?: NullBooleanConfig;\n validators?: ((data: any) => ResourceValidatorFn[]) | ResourceValidatorFn[];\n readOnly?: boolean;\n prefixes?: Affix[];\n suffixes?: Affix[];\n shouldRender?: ((data: any) => boolean) | boolean;\n nullIfConditionallyHidden?: boolean;\n}\nexport interface FieldElement {\n type: 'field';\n name: string;\n label: string;\n cols: ColSize;\n class: string;\n enumeratedConfig: EnumeratedConfig;\n default: FieldDefault;\n nullBooleanConfig: NullBooleanConfig;\n /**\n * A list of validators that must pass to allow a field to be submitted.\n * Utilize existing validators in the resourceValidators object, and\n * add any new or custom validators to it\n */\n validators: ((data: any) => ResourceValidatorFn[]) | ResourceValidatorFn[];\n readOnly: boolean;\n prefixes: Affix[];\n suffixes: Affix[];\n /**\n * shouldRender is used to determine if the element should be\n * displayed to users.\n * When assigning shouldRender a function, the first argument\n * is the current state of the resource being displayed\n */\n shouldRender: ((data: any) => boolean) | boolean;\n /** If shouldRender is NOT a function, this property does nothing\n * If shouldRender is a function, this property\n * determines whether the form control associated\n * with this config element should have its value\n * set to null if shouldRender hides it (returns false)\n */\n nullIfConditionallyHidden: boolean;\n}\n\nexport function field(config: FieldElementOptions): FieldElement {\n return {\n ...fieldElementDefaults,\n ...config,\n } satisfies FieldElement;\n}\nexport const fieldElementDefaults = {\n type: 'field',\n name: '',\n label: '',\n cols: 6,\n class: '',\n enumeratedConfig: { ...enumeratedConfigDefaults },\n default: null,\n validators: [],\n nullBooleanConfig: { ...nullBooleanConfigDefaults },\n readOnly: false,\n prefixes: [],\n suffixes: [],\n shouldRender: true,\n nullIfConditionallyHidden: false,\n} satisfies FieldElement;\n\n/**\n * RouteData is used to define the route for a config\n * route: the route for the config\n * hasViewRoute: when true, a route will be created for route/:uuid\n */\nexport interface RootRouteData {\n route?: string;\n hasViewRoute?: boolean;\n}\n\nexport interface RPCConfigOptions {\n label: string;\n afterMethodRedirect?: string;\n conditions: {\n field: FieldName;\n matchValues: string[];\n }[];\n methodBodyTemplate?: any;\n successMessage?: string;\n elements?: ConfigElement[];\n placement?: RPCPlacement;\n method: Method;\n customComponent?: ComponentConfig;\n refreshResources?: Resource[];\n defaultModalWidth?: string;\n shouldRender?: () => boolean;\n}\nexport interface RPCConfig {\n label: string;\n afterMethodRedirect: string | string[];\n conditions: {\n field: FieldName;\n matchValues: string[];\n }[];\n methodBodyTemplate: any;\n method: Method;\n successMessage: string;\n elements: ConfigElement[];\n placement: RPCPlacement;\n customComponent: ComponentConfig;\n refreshResources: Resource[];\n defaultModalWidth: string;\n shouldRender: () => boolean;\n}\nexport function rpcConfig(config: RPCConfigOptions): RPCConfig {\n return {\n ...rpcConfigDefaults,\n ...config,\n } satisfies RPCConfig;\n}\nexport const rpcConfigDefaults = {\n label: '',\n afterMethodRedirect: '',\n conditions: [] as {\n field: FieldName;\n matchValues: string[];\n }[],\n methodBodyTemplate: {} as any,\n successMessage: '',\n elements: [] as ConfigElement[],\n placement: 'end' as RPCPlacement,\n method: '' as Method,\n customComponent: {} as ComponentConfig,\n refreshResources: [] as Resource[],\n defaultModalWidth: '',\n shouldRender: (): boolean => true,\n} satisfies RPCConfig;\n\nexport interface RPCBaseFormData {\n elements: FieldElement[];\n label: string;\n method: Method;\n}\n\n// Config is the base type that all configurations should start with\nexport interface RootConfigOptions {\n routeData?: RootRouteData;\n nav?: {\n navItem: MenuItem;\n group?: string;\n };\n parentConfig: ParentResourceConfig;\n relatedConfigs?: ChildResourceConfig[];\n rpcConfigs?: RPCConfig[];\n}\nexport interface RootConfig {\n routeData: RootRouteData;\n nav: {\n navItem: MenuItem;\n group?: string;\n };\n parentConfig: ParentResourceConfig;\n relatedConfigs: ChildResourceConfig[];\n rpcConfigs?: RPCConfig[];\n}\nexport const rootConfigDefaults = {\n routeData: {} as RootRouteData,\n nav: {\n navItem: {} as MenuItem,\n },\n parentConfig: {} as ParentResourceConfig,\n relatedConfigs: [] as ChildResourceConfig[],\n rpcConfigs: [] as RPCConfig[],\n} satisfies RootConfig;\n\nexport function rootConfig(config: RootConfigOptions): RootConfig {\n return {\n ...rootConfigDefaults,\n ...config,\n } satisfies RootConfig;\n}\n\n// Base type config is the base type for all resource configurations\nexport interface BaseConfigOptions {\n title?: string;\n createTitle?: string;\n createButtonLabel?: string;\n primaryResource: Resource;\n parentClass?: string;\n fieldClass?: string;\n elements: ConfigElement[];\n createConfig?: ConfigType;\n parentRelation?: {\n parentKey: FieldName;\n childKey: FieldName;\n };\n showBackButton?: boolean;\n createNavigation?: string[];\n}\nexport interface BaseConfig {\n title: string;\n createTitle: string;\n createButtonLabel: string;\n primaryResource: Resource;\n parentClass: string;\n fieldClass: string;\n elements: ConfigElement[];\n createConfig: ConfigType;\n parentRelation: {\n parentKey: FieldName;\n childKey: FieldName;\n };\n showBackButton: boolean;\n createNavigation: string[];\n}\n\n// Available components for a component config\nexport type AvailableComponents = 'SwitchResolver';\n\n// Available param types for a component config\nexport type ConfigParam = SwitchConfigParam;\n\n// Custom component config renders a custom component and supplies params to it\nexport interface ComponentConfigOptions {\n // todo: it's weird that we have a primary resource here. Would be nice to remove but this adds a null check to all other configs\n primaryResource: Resource;\n component: AvailableComponents;\n params?: ConfigParam;\n relatedConfig?: ParentResourceConfig[];\n shouldRenderActions?: Record<'edit' | 'delete' | 'create', (data: any) => boolean>;\n}\nexport interface ComponentConfig {\n type: 'Component';\n primaryResource: Resource;\n component: AvailableComponents;\n params: ConfigParam;\n relatedConfig: ParentResourceConfig[];\n shouldRenderActions: Record<'edit' | 'delete' | 'create', (data: any) => boolean>;\n}\nexport function componentConfig(config: ComponentConfigOptions): ComponentConfig {\n return {\n ...componentConfigDefaults,\n ...config,\n } satisfies ComponentConfig;\n}\nexport const componentConfigDefaults = {\n type: 'Component',\n primaryResource: '' as Resource,\n component: 'SwitchResolver' as AvailableComponents,\n params: {\n cases: [],\n } satisfies ConfigParam,\n relatedConfig: [] as ParentResourceConfig[],\n shouldRenderActions: {\n create: (): boolean => true,\n edit: (): boolean => true,\n delete: (): boolean => true,\n },\n} satisfies ComponentConfig;\n\n// A switch is a component type that allows for conditional rendering of child components based on the value of a parent field\n// When parentData[c.parentField] equals c.caseId render the caseConfig with parentData[c.childId] as the uuid\nexport interface switchCase {\n caseId: string;\n parentField: string;\n childId: string;\n config: ChildResourceConfig;\n}\nexport interface SwitchConfigParamOptions {\n cases: switchCase[];\n}\nexport interface SwitchConfigParam {\n cases: switchCase[];\n}\nexport function switchParams(config: SwitchConfigParamOptions): SwitchConfigParam {\n return {\n ...switchParamsDefaults,\n ...config,\n } satisfies SwitchConfigParam;\n}\nexport const switchParamsDefaults = {\n cases: [] as switchCase[],\n} satisfies SwitchConfigParam;\n\nexport interface ListViewConfigOptions extends BaseConfigOptions {\n showViewButton?: boolean;\n loadCreatedResource?: boolean;\n collapsible?: boolean;\n overrideResource?: Resource;\n searchable?: boolean;\n enableRowExpansion?: boolean;\n rowExpansionConfig?: ChildResourceConfig;\n requireSearchToDisplayResults?: boolean;\n listColumns: ColumnConfig[];\n relatedConfigs?: ChildResourceConfig[];\n viewResource?: Resource | string;\n actionType?: ActionType;\n /* eslint-disable @typescript-eslint/no-explicit-any */\n filter?: (parentResource: any) => string;\n disableCacheForFilterPii?: boolean;\n rpcConfigs?: RPCConfig[];\n sorts?: FieldSort[];\n shouldRenderActions?: Record<'edit' | 'delete' | 'create', (data: any) => boolean>;\n}\nexport interface ListViewConfig extends BaseConfig {\n type: 'ListView';\n showViewButton: boolean;\n loadCreatedResource: boolean;\n collapsible: boolean;\n overrideResource: Resource;\n searchable: boolean;\n enableRowExpansion: boolean;\n rowExpansionConfig: ChildResourceConfig;\n requireSearchToDisplayResults: boolean;\n listColumns: ColumnConfig[];\n relatedConfigs: ChildResourceConfig[];\n viewResource: Resource | string;\n actionType: ActionType;\n /* eslint-disable @typescript-eslint/no-explicit-any */\n filter: (parentResource: any) => string;\n disableCacheForFilterPii: boolean;\n rpcConfigs?: RPCConfig[];\n sorts: FieldSort[];\n shouldRenderActions: Record<'edit' | 'delete' | 'create', (data: any) => boolean>;\n}\n\nexport function listViewConfig(config: ListViewConfigOptions): ListViewConfig {\n return {\n ...listViewConfigDefaults,\n ...config,\n } satisfies ListViewConfig;\n}\nexport const listViewConfigDefaults = {\n title: '',\n primaryResource: '' as Resource,\n type: 'ListView',\n createTitle: '',\n createButtonLabel: 'Create',\n loadCreatedResource: false,\n showViewButton: true,\n collapsible: false,\n listColumns: [],\n elements: [],\n parentClass: '',\n fieldClass: '',\n createConfig: {} as ListViewConfig,\n createNavigation: [],\n relatedConfigs: [],\n parentRelation: {\n parentKey: '' as FieldName,\n childKey: '' as FieldName,\n },\n overrideResource: '' as Resource,\n searchable: false,\n enableRowExpansion: false,\n rowExpansionConfig: {} as ChildResourceConfig,\n requireSearchToDisplayResults: false,\n showBackButton: true,\n filter: (): string => '',\n disableCacheForFilterPii: false,\n sorts: [] as FieldSort[],\n viewResource: '' as Resource,\n actionType: 'function' as ActionType,\n rpcConfigs: [],\n shouldRenderActions: {\n create: (): boolean => true,\n edit: (): boolean => true,\n delete: (): boolean => true,\n },\n} satisfies ListViewConfig;\n\nexport type ViewType = 'OneToOne' | 'OneToMany';\n\nexport interface ViewConfigOptions extends BaseConfigOptions {\n collapsible?: boolean;\n connectorResource?: Resource;\n relatedConfigs?: ChildResourceConfig[];\n rpcConfigs?: RPCConfig[];\n shouldRenderActions?: Record<'edit' | 'delete' | 'create', (data: any) => boolean>;\n}\nexport interface ViewConfig extends BaseConfig {\n type: 'View';\n collapsible: boolean;\n // todo: remove this comment once full documentation has been added. Populate this value when a database view resource is used to connect the ViewConfig's parent resource to its primary resource\n connectorResource: Resource;\n rpcConfigs?: RPCConfig[];\n relatedConfigs: ChildResourceConfig[];\n /** A set of functions that allows for\n * conditional display of non-RPC\n * actions based on the pristine state of the resource\n * (if such a state is applicable. Creation for example won't\n * have such data)\n * This is separate from ABAC control which takes\n * precedence and is based on a user's attributes\n */\n shouldRenderActions: Record<'edit' | 'delete' | 'create', (data: any) => boolean>;\n}\n\nexport function viewConfig(config: ViewConfigOptions): ViewConfig {\n return {\n ...viewConfigDefaults,\n ...config,\n } satisfies ViewConfig;\n}\nexport const viewConfigDefaults = {\n title: '',\n primaryResource: '' as Resource,\n type: 'View',\n createTitle: '',\n createButtonLabel: 'Create',\n parentClass: '',\n fieldClass: '',\n elements: [],\n collapsible: true,\n connectorResource: '' as Resource,\n relatedConfigs: [],\n createConfig: {} as ViewConfig,\n shouldRenderActions: {\n create: (): boolean => true,\n edit: (): boolean => true,\n delete: (): boolean => true,\n },\n createNavigation: [],\n parentRelation: {\n parentKey: '' as FieldName,\n childKey: '' as FieldName,\n },\n showBackButton: true,\n rpcConfigs: [],\n} satisfies ViewConfig;\n\nexport interface arrayConfigOptions {\n iteratedConfig: ChildResourceConfig;\n viewType?: ViewType;\n collapsible?: boolean;\n createConfig?: ConfigType;\n connectorResource?: Resource;\n connectorField?: FieldName;\n primaryResource: Resource;\n listFilter: (parentResource: any) => string;\n disableCacheForFilterPii?: boolean;\n sorts?: FieldSort[];\n title?: string;\n createButtonLabel?: string;\n limit?: number;\n shouldRenderActions?: Record<'edit' | 'delete' | 'create', (data: any) => boolean>;\n}\nexport interface ArrayConfig {\n type: 'Array';\n iteratedConfig: ChildResourceConfig;\n viewType: ViewType;\n collapsible: boolean;\n createConfig: ConfigType;\n connectorResource: Resource;\n connectorField: FieldName;\n primaryResource: Resource;\n listFilter: (parentResource: any) => string;\n disableCacheForFilterPii: boolean;\n sorts: FieldSort[];\n title: string;\n createButtonLabel: string;\n shouldRenderActions: Record<'edit' | 'delete' | 'create', (data: any) => boolean>;\n limit: number;\n}\nexport function arrayConfig(config: arrayConfigOptions): ArrayConfig {\n return {\n ...arrayConfigDefaults,\n ...config,\n } satisfies ArrayConfig;\n}\nexport const arrayConfigDefaults = {\n type: 'Array',\n iteratedConfig: {} as ChildResourceConfig,\n viewType: 'OneToMany' as ViewType,\n collapsible: true,\n createConfig: {} as ViewConfig,\n connectorResource: '' as Resource,\n connectorField: '' as FieldName,\n primaryResource: '' as Resource,\n listFilter: (): string => '',\n disableCacheForFilterPii: false,\n sorts: [] as FieldSort[],\n title: '',\n createButtonLabel: 'Create',\n limit: Infinity,\n shouldRenderActions: {\n create: (): boolean => true,\n edit: (): boolean => true,\n delete: (): boolean => true,\n },\n} satisfies ArrayConfig;\n","export enum AlertLevel {\n ERROR = 'warn',\n INFO = 'accent',\n SUCCESS = 'success',\n}\n\nexport interface CreateNotificationMessage {\n duration?: number;\n message: string;\n link: string;\n level: AlertLevel;\n}\n\nexport interface NotificationMessage {\n id: number;\n duration?: number;\n message: string;\n link: string;\n level: AlertLevel;\n}\n","type Brand<K, T> = K & { __brand: T };\n\nexport type Permission = Brand<string, 'Permission'>;\nexport type Resource = Brand<string, 'Resource'>;\nexport type Domain = Brand<string, 'Domain'>;\nexport type FieldName = Brand<string, 'FieldName'>;\nexport type Method = Brand<string, 'Method'>;\nexport type DomainPermissions = Record<Domain, Record<Resource, Record<Permission, Permissions>>>;\n\nexport interface PermissionScope {\n resource: Resource;\n permission: Permission;\n domain: Domain;\n}\n\nexport const ReadPermission = 'Read' as Permission;\nexport const UpdatePermission = 'Update' as Permission;\n","// Meta interfaces for resources and methods\n// This file exists to break circular dependencies between types and ccc-resource\n\nimport { Resource } from './permissions';\n\nexport type ValidDisplayTypes =\n | 'boolean'\n | 'nullboolean'\n | 'number'\n | 'string'\n | 'date'\n | 'enumerated'\n | 'link'\n | 'uuid'\n | 'civildate';\n\nexport type ValidRPCTypes = ValidDisplayTypes | `${ValidDisplayTypes}[]`;\n\nexport interface RPCFieldMeta {\n fieldName: string;\n displayType: ValidRPCTypes;\n enumeratedResource?: Resource;\n}\n\nexport interface MethodMeta {\n route: string;\n fields: RPCFieldMeta[];\n}\n\nexport interface FieldMeta {\n fieldName: string;\n /** Indicates whether the field is required and only applies during resource creation.\n * Use the validators config parameter in all other contexts\n */\n required: boolean;\n primaryKey?: { ordinalPosition: number };\n displayType: ValidDisplayTypes;\n enumeratedResource?: Resource;\n isIndex: boolean;\n}\n\nexport interface ResourceMeta {\n route: string;\n consolidatedRoute?: string;\n listDisabled?: boolean;\n readDisabled?: boolean;\n createDisabled?: boolean;\n updateDisabled?: boolean;\n deleteDisabled?: boolean;\n substringSearchParameter?: string;\n fields: FieldMeta[];\n}\n\nexport type Meta = MethodMeta | ResourceMeta;\n","import { InjectionToken } from '@angular/core';\nimport { Domain, Permission, Resource } from './permissions';\nimport { MethodMeta, ResourceMeta } from './resource-meta';\n\n/**\n * The base URL for API requests (e.g., 'https://api.example.com/').\n */\nexport const BASE_URL = new InjectionToken<string>('BASE_URL');\n\n/**\n * The path to the frontend login page (e.g., '/login').\n */\nexport const FRONTEND_LOGIN_PATH = new InjectionToken<string>('FRONTEND_LOGIN_PATH');\n\n/**\n * The path to the session endpoint (e.g., 'user/session').\n */\nexport const SESSION_PATH = new InjectionToken<string>('SESSION_PATH');\n\n/**\n * The base URL for API requests (e.g., '/api').\n */\nexport const API_URL = new InjectionToken<string>('API_URL');\n\nexport const PERMISSION_REQUIRED = new InjectionToken<(resource: Resource, permission: Permission) => boolean>(\n 'PERMISSION_REQUIRED',\n);\n\nexport const AVAILABLE_PERMISSIONS = new InjectionToken<{\n Create: Permission;\n Delete: Permission;\n List: Permission;\n Read: Permission;\n Update: Permission;\n}>('AVAILABLE_PERMISSIONS');\nexport const AVAILABLE_DOMAINS = new InjectionToken<Record<string, Domain>[]>('AVAILABLE_DOMAINS');\n\nexport const RESOURCE_META = new InjectionToken<(resource: Resource) => ResourceMeta>('RESOURCE_META');\nexport const METHOD_META = new InjectionToken<(method: string) => MethodMeta>('METHOD_META');\n\nexport const IDLE_SESSION_DURATION = new InjectionToken<number>('IDLE_SESSION_DURATION');\nexport const IDLE_WARNING_DURATION = new InjectionToken<number>('IDLE_WARNING_DURATION');\nexport const IDLE_KEEPALIVE_DURATION = new InjectionToken<number>('IDLE_KEEPALIVE_DURATION');\n","import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';\n\nexport const validatorsPresent = (\n control: AbstractControl<unknown, unknown>,\n validators: ValidatorFn[],\n previousValidatorCount: number,\n): boolean => {\n if (validators.length === previousValidatorCount) {\n return true;\n }\n\n let hasAllValidators = true;\n for (const validator of validators) {\n if (!control.hasValidator(validator)) {\n hasAllValidators = false;\n break;\n }\n }\n return hasAllValidators;\n};\n\nexport const requiredIf = (predicate: () => boolean, validator: ValidatorFn) => {\n return (formControl: AbstractControl): ValidationErrors | null => {\n if (!formControl.parent) {\n return null;\n }\n if (predicate()) {\n return validator(formControl);\n }\n return null;\n };\n};\n\ndeclare const __singletonValidatorBrand: unique symbol;\nexport type ResourceValidatorFn = ValidatorFn & {\n readonly [__singletonValidatorBrand]: true;\n};\nexport function createResourceValidator(validator: ValidatorFn): ResourceValidatorFn {\n return validator as ResourceValidatorFn;\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
@@ -27,10 +27,10 @@ class AlertComponent {
|
|
|
27
27
|
this.errors.dismissGlobalNotification(this.error);
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
31
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
30
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: AlertComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
31
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.2", type: AlertComponent, isStandalone: true, selector: "ccc-alert", inputs: { error: "error" }, outputs: { dismiss: "dismiss" }, ngImport: i0, template: "<div class=\"alert\" [ngClass]=\"error.level\">\n <div class=\"message\">\n <span>{{ error.message }}</span>\n </div>\n <div class=\"alert-end\">\n @if (error.link) {\n <span [routerLink]=\"error.link\" class=\"link\">View</span>\n }\n <button (click)=\"dismissAlert()\" mat-icon-button aria-label=\"Close Alert\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n</div>\n", styles: [".alert{margin:auto;border:1px solid;max-width:450px;border-radius:5px;background-color:#d3d3d3;display:flex;flex-direction:row;align-items:center;justify-content:space-between}.message{padding-left:15px;max-width:400px;display:flex;justify-content:space-between}.alert-end{display:flex;flex-direction:row;align-items:center;gap:5px}.link{cursor:pointer}.link:hover{text-decoration:underline}.warn{border-color:red;background-color:#fff5f4}.accent{border-color:#dfb51d;background-color:#fff8e0}.success{border-color:#4caf50;background-color:#f0fff0}\n"], dependencies: [{ kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i4.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }] });
|
|
32
32
|
}
|
|
33
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
33
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: AlertComponent, decorators: [{
|
|
34
34
|
type: Component,
|
|
35
35
|
args: [{ selector: 'ccc-alert', imports: [MatIconModule, MatButtonModule, CommonModule, RouterModule], template: "<div class=\"alert\" [ngClass]=\"error.level\">\n <div class=\"message\">\n <span>{{ error.message }}</span>\n </div>\n <div class=\"alert-end\">\n @if (error.link) {\n <span [routerLink]=\"error.link\" class=\"link\">View</span>\n }\n <button (click)=\"dismissAlert()\" mat-icon-button aria-label=\"Close Alert\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n</div>\n", styles: [".alert{margin:auto;border:1px solid;max-width:450px;border-radius:5px;background-color:#d3d3d3;display:flex;flex-direction:row;align-items:center;justify-content:space-between}.message{padding-left:15px;max-width:400px;display:flex;justify-content:space-between}.alert-end{display:flex;flex-direction:row;align-items:center;gap:5px}.link{cursor:pointer}.link:hover{text-decoration:underline}.warn{border-color:red;background-color:#fff5f4}.accent{border-color:#dfb51d;background-color:#fff8e0}.success{border-color:#4caf50;background-color:#f0fff0}\n"] }]
|
|
36
36
|
}], propDecorators: { error: [{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cccteam-ccc-lib-src-ui-alert.mjs","sources":["../../../projects/ccc-lib/src/ui-alert/alert.component.ts","../../../projects/ccc-lib/src/ui-alert/alert.component.html","../../../projects/ccc-lib/src/ui-alert/cccteam-ccc-lib-src-ui-alert.ts"],"sourcesContent":["import { CommonModule } from '@angular/common';\nimport { Component, EventEmitter, Input, OnInit, Output, inject } from '@angular/core';\nimport { MatButtonModule } from '@angular/material/button';\nimport { MatIconModule } from '@angular/material/icon';\nimport { RouterModule } from '@angular/router';\nimport { NotificationMessage } from '@cccteam/ccc-lib/src/types';\nimport { NotificationService } from '@cccteam/ccc-lib/src/ui-notification-service';\n\n@Component({\n selector: 'ccc-alert',\n templateUrl: './alert.component.html',\n styleUrls: ['./alert.component.scss'],\n imports: [MatIconModule, MatButtonModule, CommonModule, RouterModule],\n})\nexport class AlertComponent implements OnInit {\n @Input({ required: true }) error!: NotificationMessage;\n @Output() dismiss = new EventEmitter();\n\n errors = inject(NotificationService);\n ngOnInit(): void {\n if (this.error.duration === undefined) {\n this.error.duration = 30000;\n }\n\n setTimeout(() => {\n this.dismissAlert();\n }, this.error.duration);\n }\n\n dismissAlert(): void {\n if (this.error.id !== undefined) {\n this.errors.dismissGlobalNotification(this.error);\n }\n }\n}\n","<div class=\"alert\" [ngClass]=\"error.level\">\n <div class=\"message\">\n <span>{{ error.message }}</span>\n </div>\n <div class=\"alert-end\">\n @if (error.link) {\n <span [routerLink]=\"error.link\" class=\"link\">View</span>\n }\n <button (click)=\"dismissAlert()\" mat-icon-button aria-label=\"Close Alert\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './
|
|
1
|
+
{"version":3,"file":"cccteam-ccc-lib-src-ui-alert.mjs","sources":["../../../projects/ccc-lib/src/ui-alert/alert.component.ts","../../../projects/ccc-lib/src/ui-alert/alert.component.html","../../../projects/ccc-lib/src/ui-alert/cccteam-ccc-lib-src-ui-alert.ts"],"sourcesContent":["import { CommonModule } from '@angular/common';\nimport { Component, EventEmitter, Input, OnInit, Output, inject } from '@angular/core';\nimport { MatButtonModule } from '@angular/material/button';\nimport { MatIconModule } from '@angular/material/icon';\nimport { RouterModule } from '@angular/router';\nimport { NotificationMessage } from '@cccteam/ccc-lib/src/types';\nimport { NotificationService } from '@cccteam/ccc-lib/src/ui-notification-service';\n\n@Component({\n selector: 'ccc-alert',\n templateUrl: './alert.component.html',\n styleUrls: ['./alert.component.scss'],\n imports: [MatIconModule, MatButtonModule, CommonModule, RouterModule],\n})\nexport class AlertComponent implements OnInit {\n @Input({ required: true }) error!: NotificationMessage;\n @Output() dismiss = new EventEmitter();\n\n errors = inject(NotificationService);\n ngOnInit(): void {\n if (this.error.duration === undefined) {\n this.error.duration = 30000;\n }\n\n setTimeout(() => {\n this.dismissAlert();\n }, this.error.duration);\n }\n\n dismissAlert(): void {\n if (this.error.id !== undefined) {\n this.errors.dismissGlobalNotification(this.error);\n }\n }\n}\n","<div class=\"alert\" [ngClass]=\"error.level\">\n <div class=\"message\">\n <span>{{ error.message }}</span>\n </div>\n <div class=\"alert-end\">\n @if (error.link) {\n <span [routerLink]=\"error.link\" class=\"link\">View</span>\n }\n <button (click)=\"dismissAlert()\" mat-icon-button aria-label=\"Close Alert\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;;;;;;;MAca,cAAc,CAAA;AACE,IAAA,KAAK;AACtB,IAAA,OAAO,GAAG,IAAI,YAAY,EAAE;AAEtC,IAAA,MAAM,GAAG,MAAM,CAAC,mBAAmB,CAAC;IACpC,QAAQ,GAAA;QACN,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,KAAK,SAAS,EAAE;AACrC,YAAA,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,KAAK;QAC7B;QAEA,UAAU,CAAC,MAAK;YACd,IAAI,CAAC,YAAY,EAAE;AACrB,QAAA,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC;IACzB;IAEA,YAAY,GAAA;QACV,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,KAAK,SAAS,EAAE;YAC/B,IAAI,CAAC,MAAM,CAAC,yBAAyB,CAAC,IAAI,CAAC,KAAK,CAAC;QACnD;IACF;uGAnBW,cAAc,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAd,cAAc,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,WAAA,EAAA,MAAA,EAAA,EAAA,KAAA,EAAA,OAAA,EAAA,EAAA,OAAA,EAAA,EAAA,OAAA,EAAA,SAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECd3B,mZAaA,EAAA,MAAA,EAAA,CAAA,wiBAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EDDY,aAAa,mLAAE,eAAe,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,aAAA,EAAA,QAAA,EAAA,sFAAA,EAAA,QAAA,EAAA,CAAA,WAAA,EAAA,WAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAE,YAAY,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,WAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAE,YAAY,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,UAAA,EAAA,QAAA,EAAA,cAAA,EAAA,MAAA,EAAA,CAAA,QAAA,EAAA,aAAA,EAAA,UAAA,EAAA,qBAAA,EAAA,OAAA,EAAA,MAAA,EAAA,YAAA,EAAA,kBAAA,EAAA,oBAAA,EAAA,YAAA,EAAA,YAAA,CAAA,EAAA,CAAA,EAAA,CAAA;;2FAEzD,cAAc,EAAA,UAAA,EAAA,CAAA;kBAN1B,SAAS;+BACE,WAAW,EAAA,OAAA,EAGZ,CAAC,aAAa,EAAE,eAAe,EAAE,YAAY,EAAE,YAAY,CAAC,EAAA,QAAA,EAAA,mZAAA,EAAA,MAAA,EAAA,CAAA,wiBAAA,CAAA,EAAA;;sBAGpE,KAAK;uBAAC,EAAE,QAAQ,EAAE,IAAI,EAAE;;sBACxB;;;AEhBH;;AAEG;;;;"}
|
|
@@ -4,11 +4,11 @@ import { NotificationService } from '@cccteam/ccc-lib/src/ui-notification-servic
|
|
|
4
4
|
|
|
5
5
|
class UiCoreService {
|
|
6
6
|
notifications = inject(NotificationService);
|
|
7
|
-
loadingSignal = signal([]);
|
|
8
|
-
sidenavOpened = signal(true);
|
|
9
|
-
currentSidenavIdentifier = signal('');
|
|
7
|
+
loadingSignal = signal([], { ...(ngDevMode ? { debugName: "loadingSignal" } : {}) });
|
|
8
|
+
sidenavOpened = signal(true, { ...(ngDevMode ? { debugName: "sidenavOpened" } : {}) });
|
|
9
|
+
currentSidenavIdentifier = signal('', { ...(ngDevMode ? { debugName: "currentSidenavIdentifier" } : {}) });
|
|
10
10
|
loading = this.loadingSignal.asReadonly();
|
|
11
|
-
isLoading = computed(() => this.loading().length > 0);
|
|
11
|
+
isLoading = computed(() => this.loading().length > 0, { ...(ngDevMode ? { debugName: "isLoading" } : {}) });
|
|
12
12
|
publishError(message) {
|
|
13
13
|
this.notifications.addGlobalNotification(message);
|
|
14
14
|
}
|
|
@@ -23,10 +23,10 @@ class UiCoreService {
|
|
|
23
23
|
toggleSidenav() {
|
|
24
24
|
this.sidenavOpened.update((opened) => !opened);
|
|
25
25
|
}
|
|
26
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
27
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
26
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: UiCoreService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
27
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: UiCoreService, providedIn: 'root' });
|
|
28
28
|
}
|
|
29
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
29
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: UiCoreService, decorators: [{
|
|
30
30
|
type: Injectable,
|
|
31
31
|
args: [{
|
|
32
32
|
providedIn: 'root',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cccteam-ccc-lib-src-ui-core-service.mjs","sources":["../../../projects/ccc-lib/src/ui-core-service/ui-core.service.ts","../../../projects/ccc-lib/src/ui-core-service/cccteam-ccc-lib-src-ui-core-service.ts"],"sourcesContent":["import { computed, inject, Injectable, signal } from '@angular/core';\nimport { CreateNotificationMessage } from '@cccteam/ccc-lib/src/types';\nimport { NotificationService } from '@cccteam/ccc-lib/src/ui-notification-service';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class UiCoreService {\n notifications = inject(NotificationService);\n loadingSignal = signal([] as string[]);\n sidenavOpened = signal(true);\n currentSidenavIdentifier = signal('');\n\n private loading = this.loadingSignal.asReadonly();\n isLoading = computed(() => this.loading().length > 0);\n\n publishError(message: CreateNotificationMessage): void {\n this.notifications.addGlobalNotification(message);\n }\n\n beginActivity(process: string): void {\n if (!this.loading().includes(process)) {\n this.loadingSignal.update((current) => [...current, process]);\n }\n }\n\n endActivity(process: string): void {\n this.loadingSignal.update((current) => current.filter((p) => p !== process));\n }\n\n toggleSidenav(): void {\n this.sidenavOpened.update((opened) => !opened);\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './
|
|
1
|
+
{"version":3,"file":"cccteam-ccc-lib-src-ui-core-service.mjs","sources":["../../../projects/ccc-lib/src/ui-core-service/ui-core.service.ts","../../../projects/ccc-lib/src/ui-core-service/cccteam-ccc-lib-src-ui-core-service.ts"],"sourcesContent":["import { computed, inject, Injectable, signal } from '@angular/core';\nimport { CreateNotificationMessage } from '@cccteam/ccc-lib/src/types';\nimport { NotificationService } from '@cccteam/ccc-lib/src/ui-notification-service';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class UiCoreService {\n notifications = inject(NotificationService);\n loadingSignal = signal([] as string[]);\n sidenavOpened = signal(true);\n currentSidenavIdentifier = signal('');\n\n private loading = this.loadingSignal.asReadonly();\n isLoading = computed(() => this.loading().length > 0);\n\n publishError(message: CreateNotificationMessage): void {\n this.notifications.addGlobalNotification(message);\n }\n\n beginActivity(process: string): void {\n if (!this.loading().includes(process)) {\n this.loadingSignal.update((current) => [...current, process]);\n }\n }\n\n endActivity(process: string): void {\n this.loadingSignal.update((current) => current.filter((p) => p !== process));\n }\n\n toggleSidenav(): void {\n this.sidenavOpened.update((opened) => !opened);\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;MAOa,aAAa,CAAA;AACxB,IAAA,aAAa,GAAG,MAAM,CAAC,mBAAmB,CAAC;AAC3C,IAAA,aAAa,GAAG,MAAM,CAAC,EAAc,2DAAC;AACtC,IAAA,aAAa,GAAG,MAAM,CAAC,IAAI,2DAAC;AAC5B,IAAA,wBAAwB,GAAG,MAAM,CAAC,EAAE,sEAAC;AAE7B,IAAA,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,UAAU,EAAE;AACjD,IAAA,SAAS,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC,MAAM,GAAG,CAAC,uDAAC;AAErD,IAAA,YAAY,CAAC,OAAkC,EAAA;AAC7C,QAAA,IAAI,CAAC,aAAa,CAAC,qBAAqB,CAAC,OAAO,CAAC;IACnD;AAEA,IAAA,aAAa,CAAC,OAAe,EAAA;QAC3B,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE;AACrC,YAAA,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,OAAO,KAAK,CAAC,GAAG,OAAO,EAAE,OAAO,CAAC,CAAC;QAC/D;IACF;AAEA,IAAA,WAAW,CAAC,OAAe,EAAA;QACzB,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,OAAO,CAAC,CAAC;IAC9E;IAEA,aAAa,GAAA;AACX,QAAA,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC,MAAM,CAAC;IAChD;uGAzBW,aAAa,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAb,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,aAAa,cAFZ,MAAM,EAAA,CAAA;;2FAEP,aAAa,EAAA,UAAA,EAAA,CAAA;kBAHzB,UAAU;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,UAAU,EAAE,MAAM;AACnB,iBAAA;;;ACND;;AAEG;;;;"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, signal, computed, Injectable } from '@angular/core';
|
|
3
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
4
|
+
import { Router } from '@angular/router';
|
|
5
|
+
import { AuthService } from '@cccteam/ccc-lib/src/auth-service';
|
|
6
|
+
import { IDLE_SESSION_DURATION, IDLE_WARNING_DURATION, IDLE_KEEPALIVE_DURATION, AlertLevel } from '@cccteam/ccc-lib/src/types';
|
|
7
|
+
import { UiCoreService } from '@cccteam/ccc-lib/src/ui-core-service';
|
|
8
|
+
import { NotificationService } from '@cccteam/ccc-lib/src/ui-notification-service';
|
|
9
|
+
import { interval } from 'rxjs';
|
|
10
|
+
|
|
11
|
+
class IdleService {
|
|
12
|
+
auth = inject(AuthService);
|
|
13
|
+
core = inject(UiCoreService);
|
|
14
|
+
router = inject(Router);
|
|
15
|
+
notifications = inject(NotificationService);
|
|
16
|
+
sessionDuration = inject(IDLE_SESSION_DURATION);
|
|
17
|
+
warningDuration = inject(IDLE_WARNING_DURATION);
|
|
18
|
+
keepAliveDuration = inject(IDLE_KEEPALIVE_DURATION);
|
|
19
|
+
idleCheckFrequency = 1000;
|
|
20
|
+
warningThreshold = this.sessionDuration - this.warningDuration;
|
|
21
|
+
isActive = signal(false, { ...(ngDevMode ? { debugName: "isActive" } : {}) });
|
|
22
|
+
lastActivityTimestamp = signal(0, { ...(ngDevMode ? { debugName: "lastActivityTimestamp" } : {}) });
|
|
23
|
+
tick = signal(Date.now(), { ...(ngDevMode ? { debugName: "tick" } : {}) }); // A signal to represent the current time
|
|
24
|
+
secondsIdle = computed(() => {
|
|
25
|
+
if (!this.isActive() || this.lastActivityTimestamp() === 0) {
|
|
26
|
+
return 0;
|
|
27
|
+
}
|
|
28
|
+
// Depends on tick() to force re-evaluation as time passes
|
|
29
|
+
return Math.floor((this.tick() - this.lastActivityTimestamp()) / 1000);
|
|
30
|
+
}, { ...(ngDevMode ? { debugName: "secondsIdle" } : {}) });
|
|
31
|
+
isWarning = computed(() => this.secondsIdle() >= this.warningThreshold, { ...(ngDevMode ? { debugName: "isWarning" } : {}) });
|
|
32
|
+
countdown = computed(() => {
|
|
33
|
+
if (!this.isWarning()) {
|
|
34
|
+
return 0;
|
|
35
|
+
}
|
|
36
|
+
const remaining = this.sessionDuration - this.secondsIdle();
|
|
37
|
+
return Math.max(0, remaining);
|
|
38
|
+
}, { ...(ngDevMode ? { debugName: "countdown" } : {}) });
|
|
39
|
+
alertId;
|
|
40
|
+
mainTickerSubscription;
|
|
41
|
+
activityEvents = ['mousedown', 'mousemove', 'keypress', 'scroll', 'touchstart', 'click'];
|
|
42
|
+
constructor() {
|
|
43
|
+
interval(this.keepAliveDuration * 1000)
|
|
44
|
+
.pipe(takeUntilDestroyed())
|
|
45
|
+
.subscribe(() => this.checkSession());
|
|
46
|
+
}
|
|
47
|
+
ngOnDestroy() {
|
|
48
|
+
this.stop();
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Starts the idle monitoring service.
|
|
52
|
+
*/
|
|
53
|
+
start() {
|
|
54
|
+
if (this.isActive()) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
this.isActive.set(true);
|
|
58
|
+
this.lastActivityTimestamp.set(Date.now());
|
|
59
|
+
this.addActivityListeners();
|
|
60
|
+
this.startMainTicker();
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Stops the idle monitoring service and cleans up timers and alerts.
|
|
64
|
+
*/
|
|
65
|
+
stop() {
|
|
66
|
+
this.isActive.set(false);
|
|
67
|
+
this.mainTickerSubscription?.unsubscribe();
|
|
68
|
+
this.removeActivityListeners();
|
|
69
|
+
this.dismissWarningAlert();
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Logs out the user due to inactivity and stops the service.
|
|
73
|
+
*/
|
|
74
|
+
logoutAndStop() {
|
|
75
|
+
this.stop();
|
|
76
|
+
this.router.navigate([this.auth.loginRoute()]);
|
|
77
|
+
this.core.publishError({
|
|
78
|
+
message: 'You have been logged out due to inactivity.',
|
|
79
|
+
level: AlertLevel.INFO,
|
|
80
|
+
link: '',
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
startMainTicker() {
|
|
84
|
+
this.mainTickerSubscription = interval(this.idleCheckFrequency).subscribe(() => {
|
|
85
|
+
this.tick.set(Date.now());
|
|
86
|
+
if (this.secondsIdle() >= this.sessionDuration) {
|
|
87
|
+
this.logoutAndStop();
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (this.isWarning()) {
|
|
91
|
+
this.showOrUpdateWarningAlert(this.countdown());
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
this.dismissWarningAlert();
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
checkSession() {
|
|
99
|
+
if (this.auth.authenticated()) {
|
|
100
|
+
this.auth.checkUserSession().subscribe({
|
|
101
|
+
next: () => {
|
|
102
|
+
if (!this.auth.authenticated()) {
|
|
103
|
+
this.logoutAndStop();
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
setLastActivity() {
|
|
110
|
+
this.lastActivityTimestamp.set(Date.now());
|
|
111
|
+
}
|
|
112
|
+
boundActivity = this.setLastActivity.bind(this);
|
|
113
|
+
addActivityListeners() {
|
|
114
|
+
this.activityEvents.forEach((event) => {
|
|
115
|
+
document.addEventListener(event, this.boundActivity, true);
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
removeActivityListeners() {
|
|
119
|
+
this.activityEvents.forEach((event) => {
|
|
120
|
+
document.removeEventListener(event, this.boundActivity, true);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
showOrUpdateWarningAlert(countdown) {
|
|
124
|
+
const message = `You will be logged out in ${countdown} seconds due to inactivity.`;
|
|
125
|
+
if (this.alertId !== undefined) {
|
|
126
|
+
this.notifications.updateNotification({ id: this.alertId, level: AlertLevel.INFO, link: '', message });
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
this.alertId = this.notifications.addGlobalNotification({
|
|
130
|
+
message,
|
|
131
|
+
level: AlertLevel.INFO,
|
|
132
|
+
link: '',
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
dismissWarningAlert() {
|
|
137
|
+
if (this.alertId !== undefined) {
|
|
138
|
+
this.notifications.dismissGlobalNotificationById(this.alertId);
|
|
139
|
+
this.alertId = undefined;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IdleService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
143
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IdleService, providedIn: 'root' });
|
|
144
|
+
}
|
|
145
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IdleService, decorators: [{
|
|
146
|
+
type: Injectable,
|
|
147
|
+
args: [{
|
|
148
|
+
providedIn: 'root',
|
|
149
|
+
}]
|
|
150
|
+
}], ctorParameters: () => [] });
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Generated bundle index. Do not edit.
|
|
154
|
+
*/
|
|
155
|
+
|
|
156
|
+
export { IdleService };
|
|
157
|
+
//# sourceMappingURL=cccteam-ccc-lib-src-ui-idle-service.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cccteam-ccc-lib-src-ui-idle-service.mjs","sources":["../../../projects/ccc-lib/src/ui-idle-service/idle.service.ts","../../../projects/ccc-lib/src/ui-idle-service/cccteam-ccc-lib-src-ui-idle-service.ts"],"sourcesContent":["import { computed, inject, Injectable, OnDestroy, signal, WritableSignal } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { Router } from '@angular/router';\nimport { AuthService } from '@cccteam/ccc-lib/src/auth-service';\nimport {\n AlertLevel,\n IDLE_KEEPALIVE_DURATION,\n IDLE_SESSION_DURATION,\n IDLE_WARNING_DURATION,\n} from '@cccteam/ccc-lib/src/types';\nimport { UiCoreService } from '@cccteam/ccc-lib/src/ui-core-service';\nimport { NotificationService } from '@cccteam/ccc-lib/src/ui-notification-service';\nimport { interval, Subscription } from 'rxjs';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class IdleService implements OnDestroy {\n private auth = inject(AuthService);\n private core = inject(UiCoreService);\n private router = inject(Router);\n private notifications = inject(NotificationService);\n\n private readonly sessionDuration = inject(IDLE_SESSION_DURATION);\n private readonly warningDuration = inject(IDLE_WARNING_DURATION);\n private readonly keepAliveDuration = inject(IDLE_KEEPALIVE_DURATION);\n private readonly idleCheckFrequency = 1000;\n private readonly warningThreshold = this.sessionDuration - this.warningDuration;\n\n public readonly isActive = signal(false);\n private lastActivityTimestamp: WritableSignal<number> = signal(0);\n private tick = signal(Date.now()); // A signal to represent the current time\n\n public readonly secondsIdle = computed(() => {\n if (!this.isActive() || this.lastActivityTimestamp() === 0) {\n return 0;\n }\n // Depends on tick() to force re-evaluation as time passes\n return Math.floor((this.tick() - this.lastActivityTimestamp()) / 1000);\n });\n\n public readonly isWarning = computed(() => this.secondsIdle() >= this.warningThreshold);\n public readonly countdown = computed(() => {\n if (!this.isWarning()) {\n return 0;\n }\n const remaining = this.sessionDuration - this.secondsIdle();\n return Math.max(0, remaining);\n });\n\n private alertId: number | undefined;\n private mainTickerSubscription: Subscription | undefined;\n\n private readonly activityEvents = ['mousedown', 'mousemove', 'keypress', 'scroll', 'touchstart', 'click'];\n\n constructor() {\n interval(this.keepAliveDuration * 1000)\n .pipe(takeUntilDestroyed())\n .subscribe(() => this.checkSession());\n }\n\n ngOnDestroy(): void {\n this.stop();\n }\n\n /**\n * Starts the idle monitoring service.\n */\n start(): void {\n if (this.isActive()) {\n return;\n }\n this.isActive.set(true);\n this.lastActivityTimestamp.set(Date.now());\n this.addActivityListeners();\n this.startMainTicker();\n }\n\n /**\n * Stops the idle monitoring service and cleans up timers and alerts.\n */\n stop(): void {\n this.isActive.set(false);\n this.mainTickerSubscription?.unsubscribe();\n this.removeActivityListeners();\n this.dismissWarningAlert();\n }\n\n /**\n * Logs out the user due to inactivity and stops the service.\n */\n logoutAndStop(): void {\n this.stop();\n\n this.router.navigate([this.auth.loginRoute()]);\n this.core.publishError({\n message: 'You have been logged out due to inactivity.',\n level: AlertLevel.INFO,\n link: '',\n });\n }\n\n private startMainTicker(): void {\n this.mainTickerSubscription = interval(this.idleCheckFrequency).subscribe(() => {\n this.tick.set(Date.now());\n\n if (this.secondsIdle() >= this.sessionDuration) {\n this.logoutAndStop();\n return;\n }\n\n if (this.isWarning()) {\n this.showOrUpdateWarningAlert(this.countdown());\n } else {\n this.dismissWarningAlert();\n }\n });\n }\n\n private checkSession(): void {\n if (this.auth.authenticated()) {\n this.auth.checkUserSession().subscribe({\n next: () => {\n if (!this.auth.authenticated()) {\n this.logoutAndStop();\n }\n },\n });\n }\n }\n\n setLastActivity(): void {\n this.lastActivityTimestamp.set(Date.now());\n }\n boundActivity = this.setLastActivity.bind(this);\n\n private addActivityListeners(): void {\n this.activityEvents.forEach((event) => {\n document.addEventListener(event, this.boundActivity, true);\n });\n }\n\n private removeActivityListeners(): void {\n this.activityEvents.forEach((event) => {\n document.removeEventListener(event, this.boundActivity, true);\n });\n }\n\n private showOrUpdateWarningAlert(countdown: number): void {\n const message = `You will be logged out in ${countdown} seconds due to inactivity.`;\n if (this.alertId !== undefined) {\n this.notifications.updateNotification({ id: this.alertId, level: AlertLevel.INFO, link: '', message });\n } else {\n this.alertId = this.notifications.addGlobalNotification({\n message,\n level: AlertLevel.INFO,\n link: '',\n });\n }\n }\n\n private dismissWarningAlert(): void {\n if (this.alertId !== undefined) {\n this.notifications.dismissGlobalNotificationById(this.alertId);\n this.alertId = undefined;\n }\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
@@ -19,7 +19,7 @@ class ApiInterceptor {
|
|
|
19
19
|
if (error.status === 401) {
|
|
20
20
|
this.ngZone.run(() => {
|
|
21
21
|
this.auth.redirectUrl.set(this.baseUrl + this.router.url);
|
|
22
|
-
this.router.navigate([
|
|
22
|
+
this.router.navigate([this.auth.loginRoute()]);
|
|
23
23
|
});
|
|
24
24
|
}
|
|
25
25
|
if (!request.context.get(CUSTOM_HTTP_REQUEST_OPTIONS).suppressGlobalError) {
|
|
@@ -35,10 +35,10 @@ class ApiInterceptor {
|
|
|
35
35
|
this.ui.endActivity(request.method + ' ' + request.url);
|
|
36
36
|
}));
|
|
37
37
|
}
|
|
38
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
39
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
38
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: ApiInterceptor, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
39
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: ApiInterceptor });
|
|
40
40
|
}
|
|
41
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
41
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: ApiInterceptor, decorators: [{
|
|
42
42
|
type: Injectable
|
|
43
43
|
}] });
|
|
44
44
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cccteam-ccc-lib-src-ui-interceptor.mjs","sources":["../../../projects/ccc-lib/src/ui-interceptor/api.interceptor.ts","../../../projects/ccc-lib/src/ui-interceptor/cccteam-ccc-lib-src-ui-interceptor.ts"],"sourcesContent":["import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';\nimport { inject, Injectable, NgZone } from '@angular/core';\nimport { Router } from '@angular/router';\nimport { AuthService } from '@cccteam/ccc-lib/src/auth-service';\nimport { AlertLevel, BASE_URL } from '@cccteam/ccc-lib/src/types';\nimport { UiCoreService } from '@cccteam/ccc-lib/src/ui-core-service';\nimport { CUSTOM_HTTP_REQUEST_OPTIONS } from '@cccteam/ccc-lib/src/util-request-options';\nimport { catchError, finalize, Observable, throwError } from 'rxjs';\n\n@Injectable()\nexport class ApiInterceptor implements HttpInterceptor {\n private ui = inject(UiCoreService);\n private auth = inject(AuthService);\n private router = inject(Router);\n private ngZone = inject(NgZone);\n private baseUrl = inject(BASE_URL);\n\n intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {\n this.ui.beginActivity(request.method + ' ' + request.url);\n\n return next.handle(request).pipe(\n catchError((error: HttpErrorResponse): Observable<HttpEvent<unknown>> => {\n if (error.status === 401) {\n this.ngZone.run(() => {\n this.auth.redirectUrl.set(this.baseUrl + this.router.url);\n this.router.navigate([
|
|
1
|
+
{"version":3,"file":"cccteam-ccc-lib-src-ui-interceptor.mjs","sources":["../../../projects/ccc-lib/src/ui-interceptor/api.interceptor.ts","../../../projects/ccc-lib/src/ui-interceptor/cccteam-ccc-lib-src-ui-interceptor.ts"],"sourcesContent":["import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';\nimport { inject, Injectable, NgZone } from '@angular/core';\nimport { Router } from '@angular/router';\nimport { AuthService } from '@cccteam/ccc-lib/src/auth-service';\nimport { AlertLevel, BASE_URL } from '@cccteam/ccc-lib/src/types';\nimport { UiCoreService } from '@cccteam/ccc-lib/src/ui-core-service';\nimport { CUSTOM_HTTP_REQUEST_OPTIONS } from '@cccteam/ccc-lib/src/util-request-options';\nimport { catchError, finalize, Observable, throwError } from 'rxjs';\n\n@Injectable()\nexport class ApiInterceptor implements HttpInterceptor {\n private ui = inject(UiCoreService);\n private auth = inject(AuthService);\n private router = inject(Router);\n private ngZone = inject(NgZone);\n private baseUrl = inject(BASE_URL);\n\n intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {\n this.ui.beginActivity(request.method + ' ' + request.url);\n\n return next.handle(request).pipe(\n catchError((error: HttpErrorResponse): Observable<HttpEvent<unknown>> => {\n if (error.status === 401) {\n this.ngZone.run(() => {\n this.auth.redirectUrl.set(this.baseUrl + this.router.url);\n this.router.navigate([this.auth.loginRoute()]);\n });\n }\n if (!request.context.get(CUSTOM_HTTP_REQUEST_OPTIONS).suppressGlobalError) {\n const message = error.error?.message ?? error.message ?? error.error;\n this.ui.publishError({\n message: message,\n level: AlertLevel.ERROR,\n link: '',\n });\n }\n\n return throwError(() => error);\n }),\n finalize(() => {\n this.ui.endActivity(request.method + ' ' + request.url);\n }),\n );\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;;;;MAUa,cAAc,CAAA;AACjB,IAAA,EAAE,GAAG,MAAM,CAAC,aAAa,CAAC;AAC1B,IAAA,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC;AAC1B,IAAA,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;AACvB,IAAA,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;AACvB,IAAA,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC;IAElC,SAAS,CAAC,OAA6B,EAAE,IAAiB,EAAA;AACxD,QAAA,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;AAEzD,QAAA,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAC9B,UAAU,CAAC,CAAC,KAAwB,KAAoC;AACtE,YAAA,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG,EAAE;AACxB,gBAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAK;AACnB,oBAAA,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC;AACzD,oBAAA,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;AAChD,gBAAA,CAAC,CAAC;YACJ;AACA,YAAA,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC,mBAAmB,EAAE;AACzE,gBAAA,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,EAAE,OAAO,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,KAAK;AACpE,gBAAA,IAAI,CAAC,EAAE,CAAC,YAAY,CAAC;AACnB,oBAAA,OAAO,EAAE,OAAO;oBAChB,KAAK,EAAE,UAAU,CAAC,KAAK;AACvB,oBAAA,IAAI,EAAE,EAAE;AACT,iBAAA,CAAC;YACJ;AAEA,YAAA,OAAO,UAAU,CAAC,MAAM,KAAK,CAAC;AAChC,QAAA,CAAC,CAAC,EACF,QAAQ,CAAC,MAAK;AACZ,YAAA,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;QACzD,CAAC,CAAC,CACH;IACH;uGAjCW,cAAc,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;2GAAd,cAAc,EAAA,CAAA;;2FAAd,cAAc,EAAA,UAAA,EAAA,CAAA;kBAD1B;;;ACTD;;AAEG;;;;"}
|
|
@@ -2,8 +2,8 @@ import * as i0 from '@angular/core';
|
|
|
2
2
|
import { signal, Injectable } from '@angular/core';
|
|
3
3
|
|
|
4
4
|
class NotificationService {
|
|
5
|
-
notificationId = signal(0);
|
|
6
|
-
_notifications = signal([]);
|
|
5
|
+
notificationId = signal(0, { ...(ngDevMode ? { debugName: "notificationId" } : {}) });
|
|
6
|
+
_notifications = signal([], { ...(ngDevMode ? { debugName: "_notifications" } : {}) });
|
|
7
7
|
notifications = this._notifications.asReadonly();
|
|
8
8
|
/**
|
|
9
9
|
* Adds a new global notification.
|
|
@@ -45,10 +45,10 @@ class NotificationService {
|
|
|
45
45
|
updateNotification(updatedNotification) {
|
|
46
46
|
this._notifications.update((current) => current.map((notification) => notification.id === updatedNotification.id ? { ...notification, ...updatedNotification } : notification));
|
|
47
47
|
}
|
|
48
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
49
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
48
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: NotificationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
49
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: NotificationService, providedIn: 'root' });
|
|
50
50
|
}
|
|
51
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
51
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: NotificationService, decorators: [{
|
|
52
52
|
type: Injectable,
|
|
53
53
|
args: [{
|
|
54
54
|
providedIn: 'root',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cccteam-ccc-lib-src-ui-notification-service.mjs","sources":["../../../projects/ccc-lib/src/ui-notification-service/notification.service.ts","../../../projects/ccc-lib/src/ui-notification-service/cccteam-ccc-lib-src-ui-notification-service.ts"],"sourcesContent":["import { Injectable, signal } from '@angular/core';\nimport { CreateNotificationMessage, NotificationMessage } from '@cccteam/ccc-lib/src/types';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class NotificationService {\n private notificationId = signal(0);\n private _notifications = signal<NotificationMessage[]>([]);\n notifications = this._notifications.asReadonly();\n\n /**\n * Adds a new global notification.\n * @param notification The notification message to add.\n * @returns The unique ID assigned to the notification.\n */\n addGlobalNotification(notification: CreateNotificationMessage): number {\n this.notificationId.update((id) => id + 1);\n const newNotification: NotificationMessage = {\n ...notification,\n id: this.notificationId(),\n };\n const existingNotification = this._notifications().find((n) => n.message === newNotification.message);\n if (existingNotification) {\n this.updateNotification({ ...existingNotification, ...newNotification });\n return existingNotification.id;\n }\n this._notifications.update((current) => [...current, newNotification]);\n return newNotification.id;\n }\n\n /**\n * Dismisses a global notification by its ID.\n * @param notificationId The ID of the notification to dismiss.\n */\n dismissGlobalNotificationById(notificationId: number): void {\n this._notifications.update((current) => current.filter((notification) => notification.id !== notificationId));\n }\n\n /**\n * Dismisses a specific global notification.\n * @param notification The notification to dismiss.\n */\n dismissGlobalNotification(notification: NotificationMessage): void {\n this.dismissGlobalNotificationById(notification.id);\n }\n\n /**\n * Updates an existing notification.\n * @param updatedNotification The notification with updated information.\n */\n updateNotification(updatedNotification: NotificationMessage): void {\n this._notifications.update((current) =>\n current.map((notification) =>\n notification.id === updatedNotification.id ? { ...notification, ...updatedNotification } : notification,\n ),\n );\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './
|
|
1
|
+
{"version":3,"file":"cccteam-ccc-lib-src-ui-notification-service.mjs","sources":["../../../projects/ccc-lib/src/ui-notification-service/notification.service.ts","../../../projects/ccc-lib/src/ui-notification-service/cccteam-ccc-lib-src-ui-notification-service.ts"],"sourcesContent":["import { Injectable, signal } from '@angular/core';\nimport { CreateNotificationMessage, NotificationMessage } from '@cccteam/ccc-lib/src/types';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class NotificationService {\n private notificationId = signal(0);\n private _notifications = signal<NotificationMessage[]>([]);\n notifications = this._notifications.asReadonly();\n\n /**\n * Adds a new global notification.\n * @param notification The notification message to add.\n * @returns The unique ID assigned to the notification.\n */\n addGlobalNotification(notification: CreateNotificationMessage): number {\n this.notificationId.update((id) => id + 1);\n const newNotification: NotificationMessage = {\n ...notification,\n id: this.notificationId(),\n };\n const existingNotification = this._notifications().find((n) => n.message === newNotification.message);\n if (existingNotification) {\n this.updateNotification({ ...existingNotification, ...newNotification });\n return existingNotification.id;\n }\n this._notifications.update((current) => [...current, newNotification]);\n return newNotification.id;\n }\n\n /**\n * Dismisses a global notification by its ID.\n * @param notificationId The ID of the notification to dismiss.\n */\n dismissGlobalNotificationById(notificationId: number): void {\n this._notifications.update((current) => current.filter((notification) => notification.id !== notificationId));\n }\n\n /**\n * Dismisses a specific global notification.\n * @param notification The notification to dismiss.\n */\n dismissGlobalNotification(notification: NotificationMessage): void {\n this.dismissGlobalNotificationById(notification.id);\n }\n\n /**\n * Updates an existing notification.\n * @param updatedNotification The notification with updated information.\n */\n updateNotification(updatedNotification: NotificationMessage): void {\n this._notifications.update((current) =>\n current.map((notification) =>\n notification.id === updatedNotification.id ? { ...notification, ...updatedNotification } : notification,\n ),\n );\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;MAMa,mBAAmB,CAAA;AACtB,IAAA,cAAc,GAAG,MAAM,CAAC,CAAC,4DAAC;AAC1B,IAAA,cAAc,GAAG,MAAM,CAAwB,EAAE,4DAAC;AAC1D,IAAA,aAAa,GAAG,IAAI,CAAC,cAAc,CAAC,UAAU,EAAE;AAEhD;;;;AAIG;AACH,IAAA,qBAAqB,CAAC,YAAuC,EAAA;AAC3D,QAAA,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;AAC1C,QAAA,MAAM,eAAe,GAAwB;AAC3C,YAAA,GAAG,YAAY;AACf,YAAA,EAAE,EAAE,IAAI,CAAC,cAAc,EAAE;SAC1B;QACD,MAAM,oBAAoB,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,KAAK,eAAe,CAAC,OAAO,CAAC;QACrG,IAAI,oBAAoB,EAAE;YACxB,IAAI,CAAC,kBAAkB,CAAC,EAAE,GAAG,oBAAoB,EAAE,GAAG,eAAe,EAAE,CAAC;YACxE,OAAO,oBAAoB,CAAC,EAAE;QAChC;AACA,QAAA,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,OAAO,KAAK,CAAC,GAAG,OAAO,EAAE,eAAe,CAAC,CAAC;QACtE,OAAO,eAAe,CAAC,EAAE;IAC3B;AAEA;;;AAGG;AACH,IAAA,6BAA6B,CAAC,cAAsB,EAAA;QAClD,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC,YAAY,KAAK,YAAY,CAAC,EAAE,KAAK,cAAc,CAAC,CAAC;IAC/G;AAEA;;;AAGG;AACH,IAAA,yBAAyB,CAAC,YAAiC,EAAA;AACzD,QAAA,IAAI,CAAC,6BAA6B,CAAC,YAAY,CAAC,EAAE,CAAC;IACrD;AAEA;;;AAGG;AACH,IAAA,kBAAkB,CAAC,mBAAwC,EAAA;AACzD,QAAA,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,OAAO,KACjC,OAAO,CAAC,GAAG,CAAC,CAAC,YAAY,KACvB,YAAY,CAAC,EAAE,KAAK,mBAAmB,CAAC,EAAE,GAAG,EAAE,GAAG,YAAY,EAAE,GAAG,mBAAmB,EAAE,GAAG,YAAY,CACxG,CACF;IACH;uGAnDW,mBAAmB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAnB,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,mBAAmB,cAFlB,MAAM,EAAA,CAAA;;2FAEP,mBAAmB,EAAA,UAAA,EAAA,CAAA;kBAH/B,UAAU;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,UAAU,EAAE,MAAM;AACnB,iBAAA;;;ACLD;;AAEG;;;;"}
|
|
@@ -17,7 +17,7 @@ class SidenavComponent {
|
|
|
17
17
|
navGroups;
|
|
18
18
|
currentNav = computed(() => {
|
|
19
19
|
return this.updateNavItems(this.ui.currentSidenavIdentifier());
|
|
20
|
-
});
|
|
20
|
+
}, { ...(ngDevMode ? { debugName: "currentNav" } : {}) });
|
|
21
21
|
/**
|
|
22
22
|
* Updates the currentNav based on the identifier
|
|
23
23
|
* @param identifier
|
|
@@ -34,10 +34,10 @@ class SidenavComponent {
|
|
|
34
34
|
}
|
|
35
35
|
return this.navGroups[identifier];
|
|
36
36
|
}
|
|
37
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
38
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
37
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: SidenavComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
38
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.2", type: SidenavComponent, isStandalone: true, selector: "ccc-sidenav", inputs: { navGroups: "navGroups" }, ngImport: i0, template: "<div class=\"nav-container\">\n <nav>\n @for (navItem of currentNav(); track navItem) {\n <ng-container *ngTemplateOutlet=\"typeRendererTemplate; context: { navItem: navItem }\"></ng-container>\n }\n </nav>\n</div>\n<ng-template #typeRendererTemplate let-navItem=\"navItem\">\n @switch (navItem.type) {\n @case ('header') {\n <ng-container [ngTemplateOutlet]=\"headerTemplate\" [ngTemplateOutletContext]=\"{ navItem: navItem }\"></ng-container>\n }\n @case ('link') {\n <ng-container [ngTemplateOutlet]=\"linkTemplate\" [ngTemplateOutletContext]=\"{ navItem: navItem }\"></ng-container>\n }\n @case ('expandable') {\n <ng-container\n [ngTemplateOutlet]=\"expandableTemplate\"\n [ngTemplateOutletContext]=\"{ navItem: navItem }\"></ng-container>\n }\n }\n</ng-template>\n<ng-template #headerTemplate let-navItem=\"navItem\">\n <div class=\"link-header\">{{ navItem.label }}</div>\n</ng-template>\n<ng-template #linkTemplate let-navItem=\"navItem\">\n <a [routerLink]=\"navItem.routerLink\" *cccHasPermission=\"navItem.permission\">\n <div class=\"nav-item\" routerLinkActive=\"active-link\">\n <div class=\"link-button\">\n <div class=\"icon\">\n <mat-icon class=\"material-icons-outlined\" [inline]=\"true\">\n {{ navItem.icon }}\n </mat-icon>\n </div>\n <div class=\"text\">\n {{ navItem.label | titlecase }}\n </div>\n </div>\n </div>\n </a>\n</ng-template>\n<ng-template #expandableTemplate let-navItem=\"navItem\">\n <div class=\"nav-item\" aria-hidden=\"true\" (click)=\"navItem.isExpanded = !navItem.isExpanded\">\n <div class=\"link-button\">\n <div class=\"icon\">\n <mat-icon class=\"material-icons-outlined\" [inline]=\"true\">\n {{ navItem.isExpanded ? 'expand_less' : 'expand_more' }}\n </mat-icon>\n </div>\n <div class=\"text\">{{ navItem.label }}</div>\n </div>\n </div>\n @if (navItem.isExpanded) {\n <div class=\"expandable-links\">\n @for (navItemChild of navItem.children; track navItemChild) {\n <ng-container *ngTemplateOutlet=\"typeRendererTemplate; context: { navItem: navItemChild }\"> </ng-container>\n }\n </div>\n }\n</ng-template>\n", styles: [".nav-container{padding:0;height:100%}nav{max-width:100%;margin:0 10px}.nav-item{width:100%;height:48px;font-size:18px;display:flex;flex-direction:column;justify-content:center;color:#003b49;padding:0 15px;position:relative}.nav-item:hover{background-color:#0000000a;transition:background-color .1s ease}.nav-item:active{background-color:#0000001a;transition:background-color .1s ease}.link-header{color:#003b49;text-transform:uppercase;font-weight:700;font-size:12px;margin:20px 0 0 5px}.link-button{display:flex;flex-direction:row;width:100%}.link-button .icon{min-width:20px;margin-right:10px;display:flex;flex-direction:column;justify-content:center}.link-button .text{margin-right:10px;text-align:left;display:flex;flex-direction:row;justify-content:left;text-decoration:capitalize}.expandable-links{display:flex;flex-direction:column;width:100%;padding-left:30px}a:active,a:link,a:visited{color:#003b49!important}a{text-decoration:none}.active-link:before{content:\"\";position:absolute;left:3px;width:5px;height:38px;background-color:#003b49}.active-link{background-color:#0000000a;position:relative}\n"], dependencies: [{ kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i2.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i2.RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "ngmodule", type: MatSidenavModule }, { kind: "directive", type: HasPermissionDirective, selector: "[cccHasPermission]", inputs: ["cccHasPermission"] }, { kind: "pipe", type: i3.TitleCasePipe, name: "titlecase" }] });
|
|
39
39
|
}
|
|
40
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
40
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: SidenavComponent, decorators: [{
|
|
41
41
|
type: Component,
|
|
42
42
|
args: [{ selector: 'ccc-sidenav', imports: [
|
|
43
43
|
MatIconModule,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cccteam-ccc-lib-src-ui-sidenav.mjs","sources":["../../../projects/ccc-lib/src/ui-sidenav/sidenav.component.ts","../../../projects/ccc-lib/src/ui-sidenav/sidenav.component.html","../../../projects/ccc-lib/src/ui-sidenav/cccteam-ccc-lib-src-ui-sidenav.ts"],"sourcesContent":["import { CommonModule } from '@angular/common';\nimport { Component, computed, inject, Input, Signal } from '@angular/core';\nimport { MatButtonModule } from '@angular/material/button';\nimport { MatExpansionModule } from '@angular/material/expansion';\nimport { MatIconModule } from '@angular/material/icon';\nimport { MatSidenavModule } from '@angular/material/sidenav';\nimport { RouterModule } from '@angular/router';\n\nimport { HasPermissionDirective } from '@cccteam/ccc-lib/src/auth-has-permission';\nimport { PermissionScope } from '@cccteam/ccc-lib/src/types';\nimport { UiCoreService } from '@cccteam/ccc-lib/src/ui-core-service';\n\nexport interface NavItem {\n type: 'link' | 'header' | 'expandable';\n routerLink?: string[];\n label: string;\n icon?: string;\n permission?: PermissionScope;\n children?: NavItem[];\n isExpanded?: boolean;\n attentionCount?: Signal<number>;\n}\n\nexport type NavGroups = Record<string, NavItem[]>;\n\n@Component({\n selector: 'ccc-sidenav',\n templateUrl: './sidenav.component.html',\n styleUrls: ['./sidenav.component.scss'],\n imports: [\n MatIconModule,\n RouterModule,\n CommonModule,\n MatExpansionModule,\n MatButtonModule,\n MatSidenavModule,\n HasPermissionDirective,\n ],\n})\nexport class SidenavComponent {\n ui = inject(UiCoreService);\n\n @Input() navGroups?: NavGroups;\n currentNav = computed(() => {\n return this.updateNavItems(this.ui.currentSidenavIdentifier());\n });\n\n /**\n * Updates the currentNav based on the identifier\n * @param identifier\n * @returns NavItem[]\n * @memberof SidenavComponent\n */\n updateNavItems(identifier: string): NavItem[] {\n if (!this.navGroups) {\n return [];\n }\n if (!this.navGroups[identifier]) {\n // pick the first one if the identifier is not found so we don't break the UI\n identifier = Object.keys(this.navGroups)[0];\n }\n return this.navGroups[identifier];\n }\n}\n","<div class=\"nav-container\">\n <nav>\n @for (navItem of currentNav(); track navItem) {\n <ng-container *ngTemplateOutlet=\"typeRendererTemplate; context: { navItem: navItem }\"></ng-container>\n }\n </nav>\n</div>\n<ng-template #typeRendererTemplate let-navItem=\"navItem\">\n @switch (navItem.type) {\n @case ('header') {\n <ng-container [ngTemplateOutlet]=\"headerTemplate\" [ngTemplateOutletContext]=\"{ navItem: navItem }\"></ng-container>\n }\n @case ('link') {\n <ng-container [ngTemplateOutlet]=\"linkTemplate\" [ngTemplateOutletContext]=\"{ navItem: navItem }\"></ng-container>\n }\n @case ('expandable') {\n <ng-container\n [ngTemplateOutlet]=\"expandableTemplate\"\n [ngTemplateOutletContext]=\"{ navItem: navItem }\"></ng-container>\n }\n }\n</ng-template>\n<ng-template #headerTemplate let-navItem=\"navItem\">\n <div class=\"link-header\">{{ navItem.label }}</div>\n</ng-template>\n<ng-template #linkTemplate let-navItem=\"navItem\">\n <a [routerLink]=\"navItem.routerLink\" *cccHasPermission=\"navItem.permission\">\n <div class=\"nav-item\" routerLinkActive=\"active-link\">\n <div class=\"link-button\">\n <div class=\"icon\">\n <mat-icon class=\"material-icons-outlined\" [inline]=\"true\">\n {{ navItem.icon }}\n </mat-icon>\n </div>\n <div class=\"text\">\n {{ navItem.label | titlecase }}\n </div>\n </div>\n </div>\n </a>\n</ng-template>\n<ng-template #expandableTemplate let-navItem=\"navItem\">\n <div class=\"nav-item\" aria-hidden=\"true\" (click)=\"navItem.isExpanded = !navItem.isExpanded\">\n <div class=\"link-button\">\n <div class=\"icon\">\n <mat-icon class=\"material-icons-outlined\" [inline]=\"true\">\n {{ navItem.isExpanded ? 'expand_less' : 'expand_more' }}\n </mat-icon>\n </div>\n <div class=\"text\">{{ navItem.label }}</div>\n </div>\n </div>\n @if (navItem.isExpanded) {\n <div class=\"expandable-links\">\n @for (navItemChild of navItem.children; track navItemChild) {\n <ng-container *ngTemplateOutlet=\"typeRendererTemplate; context: { navItem: navItemChild }\"> </ng-container>\n }\n </div>\n }\n</ng-template>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './
|
|
1
|
+
{"version":3,"file":"cccteam-ccc-lib-src-ui-sidenav.mjs","sources":["../../../projects/ccc-lib/src/ui-sidenav/sidenav.component.ts","../../../projects/ccc-lib/src/ui-sidenav/sidenav.component.html","../../../projects/ccc-lib/src/ui-sidenav/cccteam-ccc-lib-src-ui-sidenav.ts"],"sourcesContent":["import { CommonModule } from '@angular/common';\nimport { Component, computed, inject, Input, Signal } from '@angular/core';\nimport { MatButtonModule } from '@angular/material/button';\nimport { MatExpansionModule } from '@angular/material/expansion';\nimport { MatIconModule } from '@angular/material/icon';\nimport { MatSidenavModule } from '@angular/material/sidenav';\nimport { RouterModule } from '@angular/router';\n\nimport { HasPermissionDirective } from '@cccteam/ccc-lib/src/auth-has-permission';\nimport { PermissionScope } from '@cccteam/ccc-lib/src/types';\nimport { UiCoreService } from '@cccteam/ccc-lib/src/ui-core-service';\n\nexport interface NavItem {\n type: 'link' | 'header' | 'expandable';\n routerLink?: string[];\n label: string;\n icon?: string;\n permission?: PermissionScope;\n children?: NavItem[];\n isExpanded?: boolean;\n attentionCount?: Signal<number>;\n}\n\nexport type NavGroups = Record<string, NavItem[]>;\n\n@Component({\n selector: 'ccc-sidenav',\n templateUrl: './sidenav.component.html',\n styleUrls: ['./sidenav.component.scss'],\n imports: [\n MatIconModule,\n RouterModule,\n CommonModule,\n MatExpansionModule,\n MatButtonModule,\n MatSidenavModule,\n HasPermissionDirective,\n ],\n})\nexport class SidenavComponent {\n ui = inject(UiCoreService);\n\n @Input() navGroups?: NavGroups;\n currentNav = computed(() => {\n return this.updateNavItems(this.ui.currentSidenavIdentifier());\n });\n\n /**\n * Updates the currentNav based on the identifier\n * @param identifier\n * @returns NavItem[]\n * @memberof SidenavComponent\n */\n updateNavItems(identifier: string): NavItem[] {\n if (!this.navGroups) {\n return [];\n }\n if (!this.navGroups[identifier]) {\n // pick the first one if the identifier is not found so we don't break the UI\n identifier = Object.keys(this.navGroups)[0];\n }\n return this.navGroups[identifier];\n }\n}\n","<div class=\"nav-container\">\n <nav>\n @for (navItem of currentNav(); track navItem) {\n <ng-container *ngTemplateOutlet=\"typeRendererTemplate; context: { navItem: navItem }\"></ng-container>\n }\n </nav>\n</div>\n<ng-template #typeRendererTemplate let-navItem=\"navItem\">\n @switch (navItem.type) {\n @case ('header') {\n <ng-container [ngTemplateOutlet]=\"headerTemplate\" [ngTemplateOutletContext]=\"{ navItem: navItem }\"></ng-container>\n }\n @case ('link') {\n <ng-container [ngTemplateOutlet]=\"linkTemplate\" [ngTemplateOutletContext]=\"{ navItem: navItem }\"></ng-container>\n }\n @case ('expandable') {\n <ng-container\n [ngTemplateOutlet]=\"expandableTemplate\"\n [ngTemplateOutletContext]=\"{ navItem: navItem }\"></ng-container>\n }\n }\n</ng-template>\n<ng-template #headerTemplate let-navItem=\"navItem\">\n <div class=\"link-header\">{{ navItem.label }}</div>\n</ng-template>\n<ng-template #linkTemplate let-navItem=\"navItem\">\n <a [routerLink]=\"navItem.routerLink\" *cccHasPermission=\"navItem.permission\">\n <div class=\"nav-item\" routerLinkActive=\"active-link\">\n <div class=\"link-button\">\n <div class=\"icon\">\n <mat-icon class=\"material-icons-outlined\" [inline]=\"true\">\n {{ navItem.icon }}\n </mat-icon>\n </div>\n <div class=\"text\">\n {{ navItem.label | titlecase }}\n </div>\n </div>\n </div>\n </a>\n</ng-template>\n<ng-template #expandableTemplate let-navItem=\"navItem\">\n <div class=\"nav-item\" aria-hidden=\"true\" (click)=\"navItem.isExpanded = !navItem.isExpanded\">\n <div class=\"link-button\">\n <div class=\"icon\">\n <mat-icon class=\"material-icons-outlined\" [inline]=\"true\">\n {{ navItem.isExpanded ? 'expand_less' : 'expand_more' }}\n </mat-icon>\n </div>\n <div class=\"text\">{{ navItem.label }}</div>\n </div>\n </div>\n @if (navItem.isExpanded) {\n <div class=\"expandable-links\">\n @for (navItemChild of navItem.children; track navItemChild) {\n <ng-container *ngTemplateOutlet=\"typeRendererTemplate; context: { navItem: navItemChild }\"> </ng-container>\n }\n </div>\n }\n</ng-template>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|