import { CommitState, isLocal } from '../models' import { Element } from '../models/element' import { ElementPrivileges, WorkRecordDataResponse } from '../services' import { ReminderWrapper } from './calendar.interface' import { ElementSchema, ElementType, ExternalFile, Template, } from './editors.interface' export type User = { uid: string cn: string sn: string } export interface ElementTypePrivilegesList { count: number 'element-types': { id: string }[] filters: { page: number 'per-page': number 'with-right': string } } export interface CloneConfig { withFiles?: boolean retainParent?: boolean } export interface NativeFile { id?: string uri: string width?: number height?: number size?: number name: string mimeType?: string } export interface BrowserFile { file: File } export type PlatformFile = NativeFile | BrowserFile export interface LocalFile { data: T id: string isLoading?: boolean extraData?: Record } export enum LinkRel { SELF_LOCAL = 'self_local', SELF = 'self', REMINDERS_LOCAL = 'reminders_local', REMINDERS = 'reminders', NAME_LOCAL = 'name_local', NAME = 'name', PARENT_LOCAL = 'parent_local', PARENT = 'parent', OWNER_LOCAL = 'owner_local', OWNER = 'owner', WORK = 'work', AUTHOR_LOCAL = 'author_local', AUTHOR = 'author', REFRESH = 'refresh', COMMENTS = 'comments', COMMENTS_LOCAL = 'comments_local', DOWNLOAD = 'download', } export type eDocuImageSize = | 'image-preview-720x360' | 'image-preview-360x360' | 'image-preview-w1536' | 'image-preview-w1024' | 'image-preview-w768' | 'image-preview-w480' | 'image-preview-m100' | 'download' export type FormDataValue = | string | number | string[] | [number, number] | undefined | null export type Operation = | RemoveOperation | AddOperation | PlusOperation | ReplaceOperation export type JsonPatchOperation = | RemoveOperation | AddOperation | ReplaceOperation export enum Operations { ADD = 'add', REMOVE = 'remove', PLUS = 'plus', REPLACE = 'replace', } export type ReplaceOperation = { op: Operations.REPLACE path: string value: NonNullable | null inheritedFrom?: string isPublic?: boolean } export type RemoveOperation = { op: Operations.REMOVE path: string inheritedFrom?: string isPublic?: boolean } export type AddOperation = { op: Operations.ADD path: string value: NonNullable | null inheritedFrom?: string isPublic?: boolean } // eDocu specific export type PlusOperation = { op: Operations.PLUS path: string value: NonNullable | null inheritedFrom?: string isPublic?: boolean } export interface RestApiLink { rel: LinkRel href: string } export type ElementMetaAttributes = { _type: ElementType author?: User hash: string links?: RestApiLink[] organization: string timestamp?: string isPublic?: boolean _element_parent?: AttributeData } export type ElementAttributeData = Record< string, AttributeData | AttributeFileData > export type ElementData = ElementAttributeData & ElementMetaAttributes export type ElementFormData = { [attribute: string]: AttributeValue | AttributeFileData | undefined } export type ElementFormDataWithoutFiles = { [attribute: string]: AttributeValue | undefined } export type ElementsTypeData = { [type: string]: AttributeDefinitions } export type ElementsTemplates = Map> export type ElementsPrivileges = Map> export interface PreparedFiles { attribute: | string | { hash: string id: string } value: LocalFile[] } export enum ElementSchemaVersion { V1 = 'v1', V2 = 'v2', } export interface ElementRaw { children?: ElementDataWrapper[] childrenCount?: number element: ElementData parent?: ElementData reminders?: Record remindersCount?: number workRecords?: WorkRecordDataResponse workRecordsCount?: number predecessors?: ElementDataWrapper[] predecessorsCount?: number references?: Record referencesCount?: number } export interface ElementMembrane extends ElementRaw { visibilityException?: VisibilityException } export interface GetElementV1Response extends ElementMembrane { schemaVersion: ElementSchemaVersion.V1 element_type: ElementTypeDefinition template: ElementTemplateV1 mode: { state: string } } export interface GetElementV2Response extends ElementMembrane { schemaVersion: ElementSchemaVersion.V2 schema: ElementSchema template: Template } export interface MembraneGetError { error: { code: string description: string } } export type ElementCreateData = { operations: Operation[] organization: { id: string } parent?: { hash: string } author?: { id: string } } export type ElementBatchCreateData = ElementCreateData & { element: { type: string } } export type StartChecklistData = { checklist: string element: string organization: string } type WithRequired = T & { [P in K]-?: T[P] } type ElementRawWithChildren = WithRequired< ElementRaw, 'children' | 'childrenCount' > export type StartChecklistResponse = { checklist: ElementRawWithChildren record: ElementRawWithChildren } export type FileBatchResponse = { 'attribute-name': string 'is-public': boolean hash: string 'file-name': string 'file-size': number 'is-relevant': boolean 'element-hash': string links: RestApiLink[] }[] export type ElementDataWrapper = { element: ElementData } export interface ElementTypeDefinition { _id: string name: string attributes: Record actions: string[] positional: boolean } export interface VisibilityException { visibilityAttr: string attrs?: string | string[] nestedAttr?: { [key: string]: NestedAttrValue[] } _unsafeDisableHashMerging?: boolean // performance optimization for nested attributes hideWorkrecords?: boolean hiddenAttrs?: 'all' | string[] } export interface NestedAttrValue { types: string[] attrs: string[] } export type AttributeDefinition = { required?: boolean type: string order?: number key: string values?: string[] modifiable?: boolean multiple?: boolean query?: string isModel?: boolean isRelationData?: boolean isRecurrence?: boolean isExternalFile?: boolean isTable?: boolean tableDefinition?: string ignoredAttributes?: string[] markdown?: boolean useCheckbox?: boolean hidden?: boolean extraConfig?: Record } export type AttributeDefinitions = { [attribute: string]: AttributeDefinition } export type AttributePrivileges = { [attribute: string]: string[] } export interface AttributeMeta { author?: User organization?: string timestamp?: string isPublic?: boolean } export interface AttributeData extends AttributeMeta { value: T } export type AttributeFileData = ( | AttributeFileValue | LocalFile )[] export interface AttributeFileValue { file: { author: { cn: string sn: string uid: string } comments: [] file_size: number filename: string hash: string organization: string relevant: boolean timestamp: string archived: boolean extraData?: Record isPublic?: boolean } links: RestApiLink[] } export interface AttributeValueTypeElement { element_name: AttributeData hash: string _type: string organization: string timestamp?: string author?: User links?: RestApiLink[] updatedAt?: string updatedBy?: User } export type AttributeValueGeo = [number, number] export type AttributeValueSingle = | string | number | boolean | Date | AttributeValueTypeElement | Element | User | AttributeValueGeo // Geo export type AttributeValueMultiple = | string[] | number[] | AttributeValueTypeElement[] | Element[] | User[] export type AttributeValue = AttributeValueSingle | AttributeValueMultiple export type DehydratedAttributeValueSingle = string | number | boolean export type DehydratedAttributeValueMultiple = string[] | number[] export type DehydratedAttributeValue = | DehydratedAttributeValueSingle | DehydratedAttributeValueMultiple export type DehydratedElementAttributeData = Record< string, AttributeData | AttributeFileData > export type DehydratedElementData = DehydratedElementAttributeData & ElementMetaAttributes export type DehydratedElementValues = Record< string, AttributeFileData | DehydratedAttributeValue > export type ILogicalOperator = | '===' | '!==' | '!!' | '!' | 'CONTAINS' | 'IN' | 'NOTIN' interface ShowHide { enabled: boolean collapsed: boolean } export interface ViewConfigCondition { attribute: string comparsionOperator: ILogicalOperator comparedValue: string | number } export interface ConditionalViewConfig { type: 'default' | 'always' | 'custom' | 'collapsed' conditions?: { items: ViewConfigCondition[] logicalOperator: 'some' | 'every' } } export type ClusterAttribute = AttributeDefinition & { visibility: ConditionalViewConfig tag?: string directiveData?: string } export interface ParsedDirective { type: string data: T // other directive types come here visibility: ConditionalViewConfig } export interface AttributeGroup { url: string id: string header: string row: number x: number width: number attributes: ClusterAttribute[] styles: { center: boolean border: number radius: number offset: number aside: boolean showHide: ShowHide visibility: ConditionalViewConfig collapse: ConditionalViewConfig } directives: ParsedDirective[] data: Partial } export interface ElementTemplateV1 { id: string name: string user: string elementType: { id: string name: string } organization: string state: string created: Date edited: Date public: boolean showHeader: boolean styles: { headerColor: string headerImage: { link: string w: number h: number } primaryColor: string secondaryColor: string linkColor: string backgroundColor: string overridable: boolean showControls: boolean showBreadcrumbs: boolean galleryMode: boolean hideHeader: boolean lighterPrimaryColor: string darkerPrimaryColor: string customCSS: string forceOverride: boolean customCSSRules: string } attributes?: { [key: string]: { reactions: { colors: TemplateAttributeReactionValue[] suffix: TemplateAttributeReactionValue[] prefix: TemplateAttributeReactionValue[] } conditions: { conditions: ConditionalViewConfig['conditions'] id: string type: 'custom' | 'always' }[] } } groups: AttributeGroup[] } export interface TemplateAttributeReactionValue { condition: string value: string type: number } export type ComposedReactions = { prefix: string suffix: string colors: { attribute?: { value?: { ['background-color']?: string } } } } export type ReactionCallback = ( accu: ComposedReactions, reaction: TemplateAttributeReactionValue, ) => void export type ParsedCluster = AttributeGroup & { data: Partial directives: ParsedDirective[] } export interface GoUrlsResponse { number: number urls: string[] } export type DataSource = 'offline-cache' | 'backend' | 'local' export const isRemoteFile = (file: unknown): file is AttributeFileValue => (file as AttributeFileValue)?.file !== undefined export const isExternalFile = (file: unknown): file is ExternalFile => (file as ExternalFile)?.type !== undefined export const isLocalFile = (file: unknown): file is LocalFile => (file as LocalFile)?.data !== undefined export const isFileData = (files: unknown): files is AttributeFileData => Array.isArray(files) && files.every((file) => isLocalFile(file) || isRemoteFile(file)) export type LocalElement = Mixin // eslint-disable-next-line @typescript-eslint/no-explicit-any export const instanceOfLocalElement = (object: any): object is LocalElement => { const candidate: LocalElement = object return ( object && candidate.state !== undefined && candidate.state !== CommitState.COMMITTED ) } export class AccessDeniedError extends Error { constructor(message?: string) { super(message ?? 'Access denied') this.name = 'AccessDeniedError' } } // eslint-disable-next-line @typescript-eslint/no-explicit-any export type AnyFunction = (...input: any[]) => A export type Mixin = InstanceType> export type Optional = Pick, K> & Omit