import { css, CSSResultGroup, html, nothing, PropertyValues, TemplateResult } from "lit"; import { AppWithContent } from "./AppWithContent"; import { AppState, FolderMode } from "./AppWithState"; import { FileInfo, FolderInfo, BreadcrumbItem } from "@labir/server"; import { provide } from "@lit/context"; import { property } from "lit/decorators.js"; import { compactContext, compactContextSetter, DisplayMode, displayModeContext, displayModeSetterContext, editTagsContext, editTagsSetterContext, showDiscussionContext, showDiscussionSetterContext, syncAnalysisContext, syncAnalysisSetterContext } from "../ClientContext"; import { ifDefined } from "lit/directives/if-defined.js"; import { t } from "i18next"; import { T } from "../../translations/Languages"; import { createRef, Ref } from "lit/directives/ref.js"; import { RegistryProviderElement } from "../../hierarchy/providers/RegistryProvider"; import { AvailableThermalPalettes } from "@labir/core"; /** * This layer provides the necessary render methods */ export abstract class AppWithRender extends AppWithContent { @property({ type: String, reflect: true }) public palette?: AvailableThermalPalettes; @property({type: Number, reflect: true}) public from?: number; @property({type: Number, reflect: true}) public to?: number; protected registryElement: Ref = createRef(); @property({ type: String, reflect: true }) @provide({ context: compactContext }) protected compact: boolean = false; @provide({ context: compactContextSetter }) protected compactSetter: (compact: boolean) => void = (compact: boolean) => { this.compact = compact; this.requestUpdate(); }; @property({ type: String, reflect: true }) @provide({ context: displayModeContext }) protected displayMode: DisplayMode = DisplayMode.GRID; @provide({ context: displayModeSetterContext }) protected displayModeSetter: (mode: DisplayMode) => void = (mode: DisplayMode) => { this.displayMode = mode; this.requestUpdate(); }; @property({ type: Boolean, reflect: true }) @provide({ context: showDiscussionContext }) protected showDiscussion: boolean = false; @provide({ context: showDiscussionSetterContext }) protected showDiscussionSetter: (columns: boolean) => void = (columns: boolean) => { this.showDiscussion = columns; this.requestUpdate(); }; @property({ type: Boolean, reflect: true }) @provide({ context: editTagsContext }) protected editableTags: boolean = false; @provide({ context: editTagsSetterContext }) protected editTagsSetter: (edit: boolean) => void = (edit: boolean) => { this.editableTags = edit; this.requestUpdate(); }; @property({ type: Boolean, reflect: true }) @provide({ context: syncAnalysisContext }) protected syncAnalyses: boolean = false; @provide({ context: syncAnalysisSetterContext }) protected syncAnalysisSetter: (sync: boolean) => void = (sync: boolean) => { this.syncAnalyses = sync; this.log("syncAnalyses", sync); this.requestUpdate(); }; protected updated(_changedProperties: PropertyValues): void { super.updated(_changedProperties); if (this.registryElement.value) { const registry = this.registryElement.value.registry; registry.manager.palette.addListener(this.UUIDContent, (palette) => { this.palette = palette; this.requestUpdate(); }); registry.range.addListener(this.UUIDContent, (range) => { this.from = range ? range.from : undefined; this.to = range ? range.to : undefined; this.requestUpdate(); }); } } public disconnectedCallback(): void { super.disconnectedCallback(); if (this.registryElement.value) { const registry = this.registryElement.value.registry; registry.manager.palette.removeListener(this.UUIDContent); registry.range.removeListener(this.UUIDContent); } } static styles?: CSSResultGroup | undefined = css` :host { } .base-info-content { display: flex; width: 100%; gap: var(--thermal-gap); flex-direction: column; } .poster { box-sizing: border-box; width: 100%; padding: var(--thermal-gap); border: 1px dashed var(--thermal-slate); border-radius: var(--thermal-radius); display: flex; flex-direction: column; align-items: center; justify-content: center; &.standalone { min-height: 200px; } } *[slot="pre"] { margin-bottom: var(--thermal-gap); } .user-layout { display: grid; grid-template-columns: 1fr 500px; gap: var(--thermal-gap); .user-layout-info, user-folders { box-sizing: border-box; padding: var(--thermal-gap); border: 1px dashed var(--thermal-slate); border-radius: var(--thermal-radius); } .user-info-field { strong { font-weight: normal; font-size: .7em; color: var(--thermal-slate); text-transform: uppercase; margin-bottom: .3em; display: block; } margin-bottom: var(--thermal-gap); } } `; protected renderContent(): TemplateResult { switch (this.state) { case AppState.LOADING: return this.renderLoading(); case AppState.POSTER: return this.renderPoster(); case AppState.USER: return this.renderUser(); case AppState.FOLDER: return this.renderFolder(); case AppState.DETAIL: return this.renderDetail(); default: return html`
Unknown state
`; } } private renderLoading(): TemplateResult { return html`
`; } private renderPoster(): TemplateResult { return html`
${this.customStateContent}
` } private renderUser(): TemplateResult { if (!this.client.auth.isLoggedIn()) { return html`
`; } return html` ${this.renderBreadcrumb()} ${this.renderUserFolders()}
`; } private renderFolder(): TemplateResult { return html` ${this.renderBreadcrumb()} this.setPath(folder.path)} slot="pre" > ${this.folder?.may_manage_files_in === true || this.folder?.may_manage_folders_in === true ? html` ${this.renderFolderCreateSubfolderDialog()} ${this.renderFolderUploadFileDialog()} ${this.renderFolderManagementButtons()} ` : nothing} ${this.hasSubfolders() ? html` this.updateGridFolders(selected)} .grid=${this.grid} > ` : nothing} ${this.hasFiles() || this.folderMode === FolderMode.GRID ? html` ` : nothing} ${this.renderDisplayMode()} ${this.hasSubfolders() && this.folderMode === FolderMode.GRID ? html` ` : nothing} ${this.hasFiles() || this.folderMode === FolderMode.GRID ? html`
` : nothing} ${this.renderFolderSubfolders()} ${this.renderFolderGrid()} ${this.renderFolderFiles()} `; } private renderDetail(): TemplateResult { return html` ${this.renderBreadcrumb()} { this.setPath(item.path) }} slot="pre" > this.setStateFile(file)} .onClose=${() => this.setPath(this.folder!.path)} style="margin-top: -1em;" > ${this.folder?.may_manage_files_in ? html` this.setStateFile(file)} variant="primary" size="md" > this.fetchContent()} variant="foreground" size="md" showLabel="true" > ` : nothing } ${this.folder!.may_manage_files_in ? html` { this.setStateFile(file); }} size="md" >` : nothing } ${this.file?.analyses && this.file.analyses?.length > 0 ? html`` : nothing} { this.setStateFile(file); }} size="md" > `; } private renderUserInfoField( label: string, value: unknown ): unknown { return html`
${label}:
${value}
`; } private renderUserFolders(): unknown { const identity = this.client.auth.getIdentity(); const userName = identity?.meta.name || identity?.user || "Uživatel"; const login = identity?.user || "unknown"; return html`
this.setPath(folder.path)} >
${this.renderUserInfoField("Uživatel", userName)} ${this.renderUserInfoField("Login", login)} { this.client.auth.logout(); }} >${t(T.logout)}
`; } private renderBreadcrumb(): TemplateResult { return html` this.setPath(folder.path)} .onUserClick=${() => this.setStateUser()} slot="pre" >`; } /** * Renders the display mode settings */ private renderDisplayMode(): unknown { if ( this.files && this.files.length > 0 && this.folder ) { return html` this.updateFiles(files)} .onChangeFile=${(file: FileInfo) => this.updateFile(file)} > this.updateFiles(files)} > `; } return nothing; } /** * Renders the folder management buttons if the user has permissions */ private renderFolderManagementButtons(): unknown { if ( this.folder && ( this.folder.may_manage_folders_in || this.folder.may_manage_files_in ) ) { return html` { this.setPath(folder.path); }} > { this.setPath(folder.path); }} >`; } return nothing; } private renderFolderCreateSubfolderDialog(): unknown { if ( this.folder && this.folder.may_manage_folders_in ) { return html` { this.fetchContent(); }} >`; } return nothing; } private renderFolderUploadFileDialog(): unknown { if (this.folder && this.folder.may_manage_files_in) { return html` { this.fetchContent(); }} >`; } return nothing; } private renderFolderSubfolders(): unknown { if ( this.subfolders && this.subfolders.length > 0 && this.folderMode !== FolderMode.GRID ) { return html` { this.setPath(folder.path); }} folderMode=${this.folderMode} >`; } return nothing; } private renderFolderGrid(): unknown { if (this.state !== AppState.FOLDER || this.folderMode !== FolderMode.GRID || !this.hasSubfolders()) { return nothing; } return html` { this.setPath(folder.path); }} .onFileClick=${(folder: FolderInfo, file: FileInfo) => { this.switchFolderInternal(folder); this.setStateFile(file); }} .onFileEdit=${(file: FileInfo) => { this.propagateFileUpdate(file); }} .onChange=${() => { if (this.path) { this.fetchGrid( this.path, this.gridFolders, this.by ) } }} .selectedFolders=${this.gridFolders} .onSelectionChange=${(selected: string[]) => this.updateGridFolders(selected)} >`; } private renderFolderFiles(): unknown { if ( this.files && this.files.length > 0 ) { return html` this.setStateFile(file)} .onFileDelete=${(file: FileInfo) => { if (this.files) { this.updateFiles( this.files.filter(f => f.fileName !== file.fileName) ); } }} .onChange=${(file: FileInfo) => this.updateFile(file)} >`; } return nothing; } }