From e18ac2143c1e8ffa6ac95bb44f95de19c6308891 Mon Sep 17 00:00:00 2001 From: Maximilian Inckmann - KIT Date: Thu, 10 Aug 2023 16:51:03 +0200 Subject: [PATCH 01/11] First working version for autoselection --- src/components.d.ts | 37 ++++++ .../display-magic/display-magic.css | 3 + .../display-magic/display-magic.stories.ts | 119 ++++++++++++++++++ .../display-magic/display-magic.tsx | 61 +++++++++ src/components/display-magic/readme.md | 39 ++++++ src/components/foldable-component/readme.md | 2 + .../intelligent-handle/intelligent-handle.tsx | 8 +- src/components/intelligent-magic/readme.md | 10 -- src/utils/FallbackType.tsx | 35 ++++++ src/utils/FoldableAction.ts | 29 +++++ src/utils/FoldableItem.ts | 46 +++++++ src/utils/GenericIdentifierType.ts | 54 ++++++++ src/utils/HandleType.tsx | 91 ++++++++++++++ src/utils/ORCIDType.tsx | 93 ++++++++++++++ src/utils/Parser.ts | 66 ++++++++++ vscode-data.json | 29 +++++ 16 files changed, 711 insertions(+), 11 deletions(-) create mode 100644 src/components/display-magic/display-magic.css create mode 100644 src/components/display-magic/display-magic.stories.ts create mode 100644 src/components/display-magic/display-magic.tsx create mode 100644 src/components/display-magic/readme.md delete mode 100644 src/components/intelligent-magic/readme.md create mode 100644 src/utils/FallbackType.tsx create mode 100644 src/utils/FoldableAction.ts create mode 100644 src/utils/FoldableItem.ts create mode 100644 src/utils/GenericIdentifierType.ts create mode 100644 src/utils/HandleType.tsx create mode 100644 src/utils/ORCIDType.tsx create mode 100644 src/utils/Parser.ts diff --git a/src/components.d.ts b/src/components.d.ts index d02d508..b5e44c9 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -35,6 +35,20 @@ export namespace Components { */ "showOrcid": boolean; } + interface DisplayMagic { + "changingColors": boolean; + "currentLevelOfSubcomponents": number; + "levelOfSubcomponents": number; + "openStatus": boolean; + "settings": { + type: string, + values: { + name: string, + value: any + }[] + }[]; + "value": string; + } interface FoldableComponent { "actions": FoldableAction[]; /** @@ -146,6 +160,12 @@ declare global { prototype: HTMLBeautifulOrcidElement; new (): HTMLBeautifulOrcidElement; }; + interface HTMLDisplayMagicElement extends Components.DisplayMagic, HTMLStencilElement { + } + var HTMLDisplayMagicElement: { + prototype: HTMLDisplayMagicElement; + new (): HTMLDisplayMagicElement; + }; interface HTMLFoldableComponentElement extends Components.FoldableComponent, HTMLStencilElement { } var HTMLFoldableComponentElement: { @@ -176,6 +196,7 @@ declare global { }; interface HTMLElementTagNameMap { "beautiful-orcid": HTMLBeautifulOrcidElement; + "display-magic": HTMLDisplayMagicElement; "foldable-component": HTMLFoldableComponentElement; "handle-highlight": HTMLHandleHighlightElement; "intelligent-handle": HTMLIntelligentHandleElement; @@ -210,6 +231,20 @@ declare namespace LocalJSX { */ "showOrcid"?: boolean; } + interface DisplayMagic { + "changingColors"?: boolean; + "currentLevelOfSubcomponents"?: number; + "levelOfSubcomponents"?: number; + "openStatus"?: boolean; + "settings"?: { + type: string, + values: { + name: string, + value: any + }[] + }[]; + "value"?: string; + } interface FoldableComponent { "actions"?: FoldableAction[]; /** @@ -315,6 +350,7 @@ declare namespace LocalJSX { } interface IntrinsicElements { "beautiful-orcid": BeautifulOrcid; + "display-magic": DisplayMagic; "foldable-component": FoldableComponent; "handle-highlight": HandleHighlight; "intelligent-handle": IntelligentHandle; @@ -326,6 +362,7 @@ declare module "@stencil/core" { export namespace JSX { interface IntrinsicElements { "beautiful-orcid": LocalJSX.BeautifulOrcid & JSXBase.HTMLAttributes; + "display-magic": LocalJSX.DisplayMagic & JSXBase.HTMLAttributes; "foldable-component": LocalJSX.FoldableComponent & JSXBase.HTMLAttributes; /** * This component highlights a handle and links to the FAIR DO Scope. diff --git a/src/components/display-magic/display-magic.css b/src/components/display-magic/display-magic.css new file mode 100644 index 0000000..5d4e87f --- /dev/null +++ b/src/components/display-magic/display-magic.css @@ -0,0 +1,3 @@ +:host { + display: block; +} diff --git a/src/components/display-magic/display-magic.stories.ts b/src/components/display-magic/display-magic.stories.ts new file mode 100644 index 0000000..c4a68d4 --- /dev/null +++ b/src/components/display-magic/display-magic.stories.ts @@ -0,0 +1,119 @@ +import {Meta, StoryObj} from "@storybook/web-components" +import {html} from "lit"; + +const meta: Meta = { + title: "display-magic", + component: "display-magic", + tags: ["autodocs"], + argTypes: { + value: { + description: "The text to display (required)", + control: { + required: true, + type: "text" + } + }, + changingColors: { + description: "Determines whether the integrated table changes colors every other row", + defaultValue: true, + control: { + type: "boolean", + } + }, + openStatus: { + description: "Determines whether the component is opened by default", + defaultValue: false, + control: { + type: "boolean", + } + }, + showSubcomponents: { + description: "Determines whether the subcomponents are shown", + defaultValue: true, + control: { + type: "boolean", + } + }, + levelOfSubcomponents: { + description: "The maximum level of subcomponents to show. ", + defaultValue: 1, + control: { + type: "number", + } + }, + currentLevelOfSubcomponents: { + description: "The current elevation level of the subcomponents.", + defaultValue: 0, + control: { + type: "number", + } + } + }, + args: { + value: "21.11152/B88E78D4-E1EE-40F7-96CE-EC1AFCFF6343", + changingColors: true, + openStatus: false, + showSubcomponents: true, + levelOfSubcomponents: 2, + currentLevelOfSubcomponents: 0, + } +} +const textDecorator = (story) => html`

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. + Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. + ${story()} Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et + dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. + Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. +

` +export default meta; +type Story = StoryObj + +export const Default: Story = { + args: { + value: "21.11152/B88E78D4-E1EE-40F7-96CE-EC1AFCFF6343", + }, +} + +export const Handle: Story = { + args: { + value: "21.11152/B88E78D4-E1EE-40F7-96CE-EC1AFCFF6343", + } +} + +export const ORCID: Story = { + args: { + value: "0009-0005-2800-4833", + } +} + +export const Fallback: Story = { + args: { + value: "sdfglhjsdfg", + }, +} + +export const HandleInText: Story = { + args: { + value: "21.11152/B88E78D4-E1EE-40F7-96CE-EC1AFCFF6343", + }, + decorators: [textDecorator], + parameters: { + docs: { + source: { + code: ` +

+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. + +Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. + +

` + } + } + } +} diff --git a/src/components/display-magic/display-magic.tsx b/src/components/display-magic/display-magic.tsx new file mode 100644 index 0000000..13b0dc8 --- /dev/null +++ b/src/components/display-magic/display-magic.tsx @@ -0,0 +1,61 @@ +import {Component, Host, h, Prop, State} from '@stencil/core'; +import {GenericIdentifierType} from "../../utils/GenericIdentifierType"; +import {FoldableItem} from "../../utils/FoldableItem"; +import {FoldableAction} from "../../utils/FoldableAction"; +import {Parser} from "../../utils/Parser"; + +@Component({ + tag: 'display-magic', + styleUrl: 'display-magic.css', + shadow: true, +}) +export class DisplayMagic { + + @Prop() value: string; + @Prop() settings: { + type: string, + values: { + name: string, + value: any + }[] + }[]; + @Prop() openStatus: boolean = false; + @Prop() changingColors: boolean = true; + @Prop() levelOfSubcomponents: number = 1; + @Prop() currentLevelOfSubcomponents: number = 0; + + @State() identifierObject: GenericIdentifierType; + @State() items: FoldableItem[] = []; + @State() actions: FoldableAction[] = []; + + // @Watch("value") async valueChanged(newValue: string) { + // const obj = await Parser.getBestFit(newValue, this.settings); + // this.identifierObject = obj; + // this.items = obj.items; + // this.actions = obj.actions; + // } + + async connectedCallback() { + const obj = await Parser.getBestFit(this.value, this.settings); + this.identifierObject = obj; + this.items = obj.items; + this.actions = obj.actions; + } + + render() { + return ( + + {this.items.length > 0 ? + + {this.identifierObject.renderPreview()} + + : this.value + } + + ); + } + +} diff --git a/src/components/display-magic/readme.md b/src/components/display-magic/readme.md new file mode 100644 index 0000000..af8dd7e --- /dev/null +++ b/src/components/display-magic/readme.md @@ -0,0 +1,39 @@ +# display-magic + + + + + + +## Properties + +| Property | Attribute | Description | Type | Default | +| ----------------------------- | -------------------------------- | ----------- | -------------------------------------------------------------- | ----------- | +| `changingColors` | `changing-colors` | | `boolean` | `true` | +| `currentLevelOfSubcomponents` | `current-level-of-subcomponents` | | `number` | `0` | +| `levelOfSubcomponents` | `level-of-subcomponents` | | `number` | `1` | +| `openStatus` | `open-status` | | `boolean` | `false` | +| `settings` | -- | | `{ type: string; values: { name: string; value: any; }[]; }[]` | `undefined` | +| `value` | `value` | | `string` | `undefined` | + + +## Dependencies + +### Depends on + +- [foldable-component](../foldable-component) + +### Graph +```mermaid +graph TD; + display-magic --> foldable-component + foldable-component --> intelligent-handle + foldable-component --> handle-highlight + intelligent-handle --> foldable-component + intelligent-handle --> handle-highlight + style display-magic fill:#f9f,stroke:#333,stroke-width:4px +``` + +---------------------------------------------- + +*Built with [StencilJS](https://stenciljs.com/)* diff --git a/src/components/foldable-component/readme.md b/src/components/foldable-component/readme.md index 93478fc..bfdc956 100644 --- a/src/components/foldable-component/readme.md +++ b/src/components/foldable-component/readme.md @@ -22,6 +22,7 @@ ### Used by + - [display-magic](../display-magic) - [intelligent-handle](../intelligent-handle) - [useful-orcid](../useful-orcid) @@ -36,6 +37,7 @@ graph TD; foldable-component --> intelligent-handle foldable-component --> handle-highlight intelligent-handle --> foldable-component + display-magic --> foldable-component useful-orcid --> foldable-component style foldable-component fill:#f9f,stroke:#333,stroke-width:4px ``` diff --git a/src/components/intelligent-handle/intelligent-handle.tsx b/src/components/intelligent-handle/intelligent-handle.tsx index a7c8e8f..e91a685 100644 --- a/src/components/intelligent-handle/intelligent-handle.tsx +++ b/src/components/intelligent-handle/intelligent-handle.tsx @@ -31,7 +31,14 @@ export class IntelligentHandle { */ @State() loadSubcomponents: boolean = false; + /** + * The private state of the items shown in the foldable-component. + */ @State() items: FoldableItem[] = []; + + /** + * The private state of the actions offered in the foldable-component. + */ @State() actions: FoldableAction[] = []; /** @@ -65,7 +72,6 @@ export class IntelligentHandle { */ @Prop() showSubcomponents: boolean = true; - /** * This method is called when the component is first connected to the DOM. * It generates the colors for the parts of the handle and stores them in the state. diff --git a/src/components/intelligent-magic/readme.md b/src/components/intelligent-magic/readme.md deleted file mode 100644 index b8fc1ca..0000000 --- a/src/components/intelligent-magic/readme.md +++ /dev/null @@ -1,10 +0,0 @@ -# intelligent-magic - - - - - - ----------------------------------------------- - -*Built with [StencilJS](https://stenciljs.com/)* diff --git a/src/utils/FallbackType.tsx b/src/utils/FallbackType.tsx new file mode 100644 index 0000000..56b9d65 --- /dev/null +++ b/src/utils/FallbackType.tsx @@ -0,0 +1,35 @@ +import {FunctionalComponent, h} from "@stencil/core"; +import {GenericIdentifierType} from "./GenericIdentifierType"; + +export class FallbackType extends GenericIdentifierType { + hasCorrectFormat(): boolean { + console.log("Fallback has correct format: " + this.value); + return true; + } + + init(): Promise { + console.log("Fallback init"); + return Promise.resolve(undefined); + } + + isResolvable(): boolean { + console.log("Fallback isn`t resolvable: " + this.value); + return false; + } + + renderBody(): FunctionalComponent { + return ( + Body: {this.value} {this.settings} + ) + } + + renderPreview(): FunctionalComponent { + return ( + Preview: {this.value} {this.settings} + ) + } + + getSettingsKey(): string { + return ""; + } +} diff --git a/src/utils/FoldableAction.ts b/src/utils/FoldableAction.ts new file mode 100644 index 0000000..2676480 --- /dev/null +++ b/src/utils/FoldableAction.ts @@ -0,0 +1,29 @@ +export class FoldableAction { + private readonly _priority: number; + private readonly _title: string; + private readonly _link: string; + private readonly _style: "primary" | "secondary" | "danger"; + + constructor(priority: number, title: string, link: string, style: "primary" | "secondary" | "danger") { + this._priority = priority; + this._title = title; + this._link = link; + this._style = style; + } + + get priority(): number { + return this._priority; + } + + get title(): string { + return this._title; + } + + get link(): string { + return this._link; + } + + get style(): "primary" | "secondary" | "danger" { + return this._style; + } +} diff --git a/src/utils/FoldableItem.ts b/src/utils/FoldableItem.ts new file mode 100644 index 0000000..6dba884 --- /dev/null +++ b/src/utils/FoldableItem.ts @@ -0,0 +1,46 @@ +export class FoldableItem { + private readonly _priority: number; + private readonly _keyTitle: string; + private readonly _value: string; + + private readonly _keyTooltip?: string; + private readonly _keyLink?: string; + private readonly _valueRegex?: RegExp; + + constructor(priority: number, keyTitle: string, value: string, keyTooltip?: string, keyLink?: string, valueRegex?: RegExp) { + this._priority = priority; + this._keyTitle = keyTitle; + this._value = value; + this._keyTooltip = keyTooltip; + this._keyLink = keyLink; + this._valueRegex = valueRegex; + } + + get priority(): number { + return this._priority; + } + + get keyTitle(): string { + return this._keyTitle; + } + + get value(): string { + return this._value; + } + + get keyTooltip(): string { + return this._keyTooltip; + } + + get keyLink(): string { + return this._keyLink; + } + + get valueRegex(): RegExp { + return this._valueRegex; + } + + isValidValue(): boolean { + return this._valueRegex.test(this._value); + } +} diff --git a/src/utils/GenericIdentifierType.ts b/src/utils/GenericIdentifierType.ts new file mode 100644 index 0000000..2dbbccd --- /dev/null +++ b/src/utils/GenericIdentifierType.ts @@ -0,0 +1,54 @@ +import {FunctionalComponent} from "@stencil/core"; +import {FoldableItem} from "./FoldableItem"; +import {FoldableAction} from "./FoldableAction"; + +export abstract class GenericIdentifierType { + private readonly _value: string; + + private _settings: { + name: string, + value: any + }[] = []; + + private _items: FoldableItem[] = []; + private _actions: FoldableAction[] = []; + + constructor(value: string) + constructor(value: string, settings?: { name: string; value: any }[]) { + this._value = value; + this._settings = settings; + console.log("GenericIdentifierType", this._value, this._settings); + } + + get value(): string { + return this._value; + } + + get settings(): { name: string; value: any }[] { + return this._settings; + } + + set settings(value: { name: string; value: any }[]) { + this._settings = value; + } + + get items(): FoldableItem[] { + return this._items; + } + + get actions(): FoldableAction[] { + return this._actions; + } + + abstract init(): Promise; + + abstract isResolvable(): boolean; + + abstract hasCorrectFormat(): boolean; + + abstract getSettingsKey(): string; + + abstract renderPreview(): FunctionalComponent; + + abstract renderBody(): FunctionalComponent; +} diff --git a/src/utils/HandleType.tsx b/src/utils/HandleType.tsx new file mode 100644 index 0000000..a556441 --- /dev/null +++ b/src/utils/HandleType.tsx @@ -0,0 +1,91 @@ +import {HSLColor} from "./HSLColor"; +import {PIDRecord} from "./PIDRecord"; +import {PID} from "./PID"; +import {PIDDataType} from "./PIDDataType"; +import {FunctionalComponent, h} from "@stencil/core"; +import {GenericIdentifierType} from "./GenericIdentifierType"; +import {FoldableItem} from "./FoldableItem"; +import {FoldableAction} from "./FoldableAction"; + +export class HandleType extends GenericIdentifierType { + private _parts: { + text: string, + color: HSLColor, + nextExists: boolean + }[] = []; + + private _pidRecord: PIDRecord; + + hasCorrectFormat(): boolean { + console.log("Checking if this is a Handle " + this.value); + return PID.isPID(this.value); + } + + async init(): Promise { + console.log("Initializing Handle " + this.value); + const pid = PID.getPIDFromString(this.value); + + // Generate the colors for the parts of the PID + this._parts = [{ + text: pid.prefix, + color: await HSLColor.generateColor(pid.prefix), + nextExists: true + }, { + text: pid.suffix, + color: await HSLColor.generateColor(pid.suffix), + nextExists: false + }] + + // Resolve the PID + const resolved = await pid.resolve(); + this._pidRecord = resolved; + for (const value of resolved.values) { + if (value.type instanceof PIDDataType) { + this.items.push(new FoldableItem(0, value.type.name, value.data.value, value.type.description, value.type.redirectURL, value.type.regex)) + } + } + + this.actions.push(new FoldableAction(0, "Open in FAIR-DOscope", `https://kit-data-manager.github.io/fairdoscope/?pid=${resolved.pid.toString()}`, "primary")) + + console.log(this._pidRecord) + console.log(this.items) + console.log(this.actions) + console.log("Finished loading..."); + return Promise.resolve(undefined); + } + + isResolvable(): boolean { + return this._pidRecord.values.length > 0; + } + + renderBody(): FunctionalComponent { + return undefined; + } + + renderPreview(): FunctionalComponent { + return ( + + {this._parts.map((element) => { + return ( + + + {element.text} + + + {element.nextExists ? "/" : ""} + + + ) + })} + + ) + } + + getSettingsKey(): string { + return "HandleConfig"; + } +} diff --git a/src/utils/ORCIDType.tsx b/src/utils/ORCIDType.tsx new file mode 100644 index 0000000..d31432f --- /dev/null +++ b/src/utils/ORCIDType.tsx @@ -0,0 +1,93 @@ +import {FunctionalComponent, h} from "@stencil/core"; +import {GenericIdentifierType} from "./GenericIdentifierType"; +import {FoldableItem} from "./FoldableItem"; +import {FoldableAction} from "./FoldableAction"; +import {ORCIDInfo} from "./ORCIDInfo"; +import {getLocaleDetail} from "./utils"; + +export class ORCIDType extends GenericIdentifierType { + + private _orcidInfo: ORCIDInfo; + + hasCorrectFormat(): boolean { + console.log("Checking if this is a ORCiD " + this.value); + return ORCIDInfo.isORCiD(this.value); + } + + async init(): Promise { + let parsed = await ORCIDInfo.getORCiDInfo(this.value); + this._orcidInfo = parsed; + + // Generate items and actions + + this.items.push(...[ + new FoldableItem(0, "ORCiD", parsed.orcid, "ORCiD is a free service for researchers to distinguish themselves by creating a unique personal identifier.", "https://orcid.org"), + new FoldableItem(0, "Family Name", parsed.familyName, "The family name of the person."), + new FoldableItem(0, "Given Names", parsed.givenNames.toString(), "The given names of the person."), + new FoldableItem(0, "Current Affiliation", parsed.getAffiliationAtString(new Date(Date.now()), true), "The current affiliation of the person."), + ]) + + // if (parsed.getAffiliationAt(this.affiliationAt) !== parsed.getAffiliationAt(new Date(Date.now()))) { + // this.items.push({ + // keyTitle: "Affiliation at " + this.affiliationAt.toLocaleDateString("en-US", { + // year: "numeric", + // month: "numeric", + // day: "numeric" + // }), + // keyTooltip: "The affiliation of the person at the given date.", + // value: parsed.getAffiliationAtString(this.affiliationAt, true), + // }) + // } + + if (parsed.emails) { + let primary = parsed.emails.filter((email) => email.primary)[0]; + let other = parsed.emails.filter((email) => !email.primary); + + // If there is a primary e-mail address, generate an item and an action to send email + if (primary) { + this.items.push(new FoldableItem(0, "Primary E-Mail address", primary.email, "The primary e-mail address of the person.")) + this.actions.push(new FoldableAction(0, "Send E-Mail", `mailto:${primary.email}`, "secondary")) + } + + // If there are other e-mail addresses, generate an item with a list of them + if (other.length > 0) this.items.push(new FoldableItem(0, "Other E-Mail addresses", other.map((email) => email.email).join(", "), "All other e-mail addresses of the person.")) + + if (parsed.preferredLocale) this.items.push(new FoldableItem(0, "Preferred Language", getLocaleDetail(parsed.preferredLocale, "language"), "The preferred locale/language of the person.")) + + for (let url of parsed.researcherUrls) { + this.items.push(new FoldableItem(0, url.name, url.url, "A link to a website specified by the person.")) + } + + if (parsed.keywords.length > 0) this.items.push(new FoldableItem(0, "Keywords", parsed.keywords.map((keyword) => keyword.content).join(", "), "Keywords specified by the person.")) + + if (parsed.biography) this.items.push(new FoldableItem(0, "Biography", parsed.biography, "The biography of the person.")) + + if (parsed.country) this.items.push(new FoldableItem(0, "Country", getLocaleDetail(parsed.country, "region"), "The country of the person.")) + + console.log(this._orcidInfo); + console.log(this.items); + return Promise.resolve(undefined); + } + } + + isResolvable(): boolean { + return this._orcidInfo.ORCiDJSON !== undefined; + } + + renderBody(): FunctionalComponent { + return undefined; + } + + renderPreview(): FunctionalComponent { + return ( + // + + ) + } + + getSettingsKey(): string { + return "ORCIDConfig"; + } +} diff --git a/src/utils/Parser.ts b/src/utils/Parser.ts new file mode 100644 index 0000000..0822653 --- /dev/null +++ b/src/utils/Parser.ts @@ -0,0 +1,66 @@ +import {GenericIdentifierType} from "./GenericIdentifierType"; +import {HandleType} from "./HandleType"; +import {FallbackType} from "./FallbackType"; +import {ORCIDType} from "./ORCIDType"; + +export class Parser { + private static readonly _dataTypes: (new(value: string, settings?: { + name: string, + value: any + }[]) => GenericIdentifierType)[] = [ + ORCIDType, + HandleType, + FallbackType, + ]; + + static async getBestFit(value: string, settings: { + type: string, values: { + name: string, + value: any + }[] + }[]): Promise { + console.log("AllTypes", this._dataTypes); + // let bestFit = this._dataTypes[this._dataTypes.length - 1]; + // console.log(new this._dataTypes[0](value)); + let bestFit = new this._dataTypes[this._dataTypes.length - 1](value) + // let bestFit = this.create(this._dataTypes[length - 1], value); + + for (let i = this._dataTypes.length - 1; i >= 0; i--) { + // if (this._dataTypes[i].prototype.hasCorrectFormat()) { + // bestFit = this._dataTypes[i]; + // } + const obj = new this._dataTypes[i](value); + // const obj = this.create(this._dataTypes[i], value); + if (obj.hasCorrectFormat()) bestFit = obj; + } + + console.log("Found bestFit", bestFit); + + // const obj = this.create(bestFit, value); + try { + const settingsKey = bestFit.getSettingsKey(); + const settingsValues = settings.find((value) => value.type === settingsKey)?.values; + if (settingsValues) bestFit.settings = settingsValues; + } catch (e) { + console.log("No settings found for", bestFit.getSettingsKey()); + } + + await bestFit.init() + return bestFit + } + + // static create( + // c: new(value: string, settings?: { + // name: string, + // value: any + // }[]) => T, + // value: string, + // settings?: { + // name: string, + // value: any + // }[]): T { + // console.log("create", c, value, settings); + // return new c(value, settings); + // } + +} diff --git a/vscode-data.json b/vscode-data.json index 78c5c5d..dc4d5d8 100644 --- a/vscode-data.json +++ b/vscode-data.json @@ -26,6 +26,35 @@ } ] }, + { + "name": "display-magic", + "description": { + "kind": "markdown", + "value": "" + }, + "attributes": [ + { + "name": "changing-colors", + "description": "" + }, + { + "name": "current-level-of-subcomponents", + "description": "" + }, + { + "name": "level-of-subcomponents", + "description": "" + }, + { + "name": "open-status", + "description": "" + }, + { + "name": "value", + "description": "" + } + ] + }, { "name": "foldable-component", "description": { From 78fdc6641fb0aa7d0fb16f3e985ec03b75e668bc Mon Sep 17 00:00:00 2001 From: Maximilian Inckmann - KIT Date: Fri, 11 Aug 2023 17:30:20 +0200 Subject: [PATCH 02/11] Implemented heuristic for different types and values; minor improvements --- src/components.d.ts | 4 + .../display-magic/display-magic.css | 3 - .../display-magic/display-magic.stories.ts | 32 ++- .../display-magic/display-magic.tsx | 267 ++++++++++++++++-- src/components/display-magic/readme.md | 14 +- .../foldable-component/foldable-component.tsx | 111 ++------ src/components/foldable-component/readme.md | 20 +- src/utils/DateType.tsx | 36 +++ src/utils/FallbackType.tsx | 11 +- src/utils/FoldableItem.ts | 16 +- src/utils/ORCIDInfo.ts | 34 ++- src/utils/ORCIDType.tsx | 32 ++- src/utils/Parser.ts | 14 + src/utils/utils.ts | 2 - vscode-data.json | 8 + 15 files changed, 436 insertions(+), 168 deletions(-) create mode 100644 src/utils/DateType.tsx diff --git a/src/components.d.ts b/src/components.d.ts index b5e44c9..a15149e 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -36,6 +36,7 @@ export namespace Components { "showOrcid": boolean; } interface DisplayMagic { + "amountOfItems": number; "changingColors": boolean; "currentLevelOfSubcomponents": number; "levelOfSubcomponents": number; @@ -47,6 +48,7 @@ export namespace Components { value: any }[] }[]; + "showSubcomponents": boolean; "value": string; } interface FoldableComponent { @@ -232,6 +234,7 @@ declare namespace LocalJSX { "showOrcid"?: boolean; } interface DisplayMagic { + "amountOfItems"?: number; "changingColors"?: boolean; "currentLevelOfSubcomponents"?: number; "levelOfSubcomponents"?: number; @@ -243,6 +246,7 @@ declare namespace LocalJSX { value: any }[] }[]; + "showSubcomponents"?: boolean; "value"?: string; } interface FoldableComponent { diff --git a/src/components/display-magic/display-magic.css b/src/components/display-magic/display-magic.css index 5d4e87f..e69de29 100644 --- a/src/components/display-magic/display-magic.css +++ b/src/components/display-magic/display-magic.css @@ -1,3 +0,0 @@ -:host { - display: block; -} diff --git a/src/components/display-magic/display-magic.stories.ts b/src/components/display-magic/display-magic.stories.ts index c4a68d4..ee87995 100644 --- a/src/components/display-magic/display-magic.stories.ts +++ b/src/components/display-magic/display-magic.stories.ts @@ -13,6 +13,12 @@ const meta: Meta = { type: "text" } }, + settings: { + description: "The settings to use for the component", + control: { + type: "object", + } + }, changingColors: { description: "Determines whether the integrated table changes colors every other row", defaultValue: true, @@ -27,6 +33,13 @@ const meta: Meta = { type: "boolean", } }, + amountOfItems: { + description: "The amount of items to show in the table", + defaultValue: 10, + control: { + type: "number", + } + }, showSubcomponents: { description: "Determines whether the subcomponents are shown", defaultValue: true, @@ -47,12 +60,15 @@ const meta: Meta = { control: { type: "number", } - } + }, + }, args: { value: "21.11152/B88E78D4-E1EE-40F7-96CE-EC1AFCFF6343", + settings: {}, changingColors: true, openStatus: false, + amountOfItems: 10, showSubcomponents: true, levelOfSubcomponents: 2, currentLevelOfSubcomponents: 0, @@ -89,6 +105,7 @@ export const Handle: Story = { export const ORCID: Story = { args: { value: "0009-0005-2800-4833", + openStatus: true, } } @@ -98,6 +115,19 @@ export const Fallback: Story = { }, } +export const ORCIDInRecord = { + args: { + value: "21.T11981/be908bd1-e049-4d35-975e-8e27d40117e6", + } +} + +export const ORCIDInRecordWithoutLimit = { + args: { + value: "21.T11981/be908bd1-e049-4d35-975e-8e27d40117e6", + amountOfItems: 100, + } +} + export const HandleInText: Story = { args: { value: "21.11152/B88E78D4-E1EE-40F7-96CE-EC1AFCFF6343", diff --git a/src/components/display-magic/display-magic.tsx b/src/components/display-magic/display-magic.tsx index 13b0dc8..f65d67a 100644 --- a/src/components/display-magic/display-magic.tsx +++ b/src/components/display-magic/display-magic.tsx @@ -21,41 +21,270 @@ export class DisplayMagic { }[]; @Prop() openStatus: boolean = false; @Prop() changingColors: boolean = true; + @Prop() amountOfItems: number = 10; @Prop() levelOfSubcomponents: number = 1; @Prop() currentLevelOfSubcomponents: number = 0; + @Prop() showSubcomponents: boolean = true; @State() identifierObject: GenericIdentifierType; @State() items: FoldableItem[] = []; @State() actions: FoldableAction[] = []; - - // @Watch("value") async valueChanged(newValue: string) { - // const obj = await Parser.getBestFit(newValue, this.settings); - // this.identifierObject = obj; - // this.items = obj.items; - // this.actions = obj.actions; - // } + @State() loadSubcomponents: boolean = false; + @State() displayStatus: "loading" | "loaded" | "error" = "loading"; + @State() tablePage: number = 0; async connectedCallback() { const obj = await Parser.getBestFit(this.value, this.settings); this.identifierObject = obj; - this.items = obj.items; - this.actions = obj.actions; + + if(this.showSubcomponents) { + this.items = obj.items; + this.items.sort((a, b) => { + if (a.priority > b.priority) return 1; + if (a.priority < b.priority) return -1; + if (a.estimatedTypePriority > b.estimatedTypePriority) return 1; + if (a.estimatedTypePriority < b.estimatedTypePriority) return -1; + }); + this.actions = obj.actions; + this.actions.sort((a, b) => a.priority - b.priority); + } + this.displayStatus = "loaded"; + } + + private toggleSubcomponents = () => { + // console.log(`currentLevelOfSubcomponents: ${this.currentLevelOfSubcomponents}, levelOfSubcomponents: ${this.levelOfSubcomponents}, showSubcomponents: ${this.showSubcomponents}`); + if (this.showSubcomponents && (this.levelOfSubcomponents - this.currentLevelOfSubcomponents > 0)) this.loadSubcomponents = !this.loadSubcomponents; + } + + private showTooltip = (event: Event) => { + let target = event.target as HTMLElement; + do { + target = target.parentElement as HTMLElement; + } while (target !== null && target.tagName !== "A") + if (target !== null) target.children[1].classList.remove("hidden"); + } + + private hideTooltip = (event: Event) => { + let target = event.target as HTMLElement; + do { + target = target.parentElement as HTMLElement; + } while (target !== null && target.tagName !== "A") + if (target !== null) target.children[1].classList.add("hidden"); } render() { return ( - - {this.items.length > 0 ? - - {this.identifierObject.renderPreview()} - - : this.value + + { + this.items.length === 0 && this.actions.length === 0 + ? this.identifierObject !== undefined + ? this.identifierObject.renderPreview() + : + + + + + Loading... {this.value} + + + //
+ // {this.identifierObject !== undefined ? this.identifierObject.renderPreview() : this.value} + //
+ :
+ + {this.identifierObject.renderPreview()} + + { + this.items.length > 0 + ?
+
+ + + + + + + + + { + this.items.map((value, index) => { + if (index >= this.amountOfItems) return; + return ( + + + + + ) + }) + } + +
KeyValue
+ + + + + + { + this.loadSubcomponents && this.showSubcomponents && !value.doNOTFold ? + + : this.showSubcomponents && this.currentLevelOfSubcomponents === this.levelOfSubcomponents && !value.doNOTFold ? + + : value.value + } +
+
+ +
+ : "" + } + {this.identifierObject.renderBody()} + { + this.actions.length > 0 ? + + { + this.actions.map((action) => { + let style = "p-1 font-semibold text-sm rounded border "; + switch (action.style) { + case "primary": + style += "bg-blue-500 text-white"; + break; + case "secondary": + style += "bg-slate-200 text-blue-500"; + break; + case "danger": + style += "bg-red-500 text-white"; + break; + } + + return ( + + {action.title} + + ) + }) + } + : "" + } +
}
- ); + ) + + + // return ( + // + // {this.items.length > 0 ? + // + // {this.identifierObject.renderPreview()} + // {/*{this.identifierObject.renderPreview()}*/} + // {/*{this.identifierObject.renderBody()}*/} + // + // : this.value + // } + // + // ); } } diff --git a/src/components/display-magic/readme.md b/src/components/display-magic/readme.md index af8dd7e..4add020 100644 --- a/src/components/display-magic/readme.md +++ b/src/components/display-magic/readme.md @@ -9,28 +9,30 @@ | Property | Attribute | Description | Type | Default | | ----------------------------- | -------------------------------- | ----------- | -------------------------------------------------------------- | ----------- | +| `amountOfItems` | `amount-of-items` | | `number` | `10` | | `changingColors` | `changing-colors` | | `boolean` | `true` | | `currentLevelOfSubcomponents` | `current-level-of-subcomponents` | | `number` | `0` | | `levelOfSubcomponents` | `level-of-subcomponents` | | `number` | `1` | | `openStatus` | `open-status` | | `boolean` | `false` | | `settings` | -- | | `{ type: string; values: { name: string; value: any; }[]; }[]` | `undefined` | +| `showSubcomponents` | `show-subcomponents` | | `boolean` | `true` | | `value` | `value` | | `string` | `undefined` | ## Dependencies +### Used by + + - [display-magic](.) + ### Depends on -- [foldable-component](../foldable-component) +- [display-magic](.) ### Graph ```mermaid graph TD; - display-magic --> foldable-component - foldable-component --> intelligent-handle - foldable-component --> handle-highlight - intelligent-handle --> foldable-component - intelligent-handle --> handle-highlight + display-magic --> display-magic style display-magic fill:#f9f,stroke:#333,stroke-width:4px ``` diff --git a/src/components/foldable-component/foldable-component.tsx b/src/components/foldable-component/foldable-component.tsx index 57b41ad..6451637 100644 --- a/src/components/foldable-component/foldable-component.tsx +++ b/src/components/foldable-component/foldable-component.tsx @@ -6,7 +6,8 @@ export type FoldableItem = { keyTooltip: string, keyLink?: string, value: string, - valueRegex?: RegExp + valueRegex?: RegExp, + valueIsFoldable?: boolean } export type FoldableAction = { @@ -22,89 +23,9 @@ export type FoldableAction = { }) export class FoldableComponent { - @Prop() items: FoldableItem[] = [ - // { - // keyTitle: "Title", - // keyTooltip: "The title of the dataset.", - // keyLink: "https://schema.org/name", - // value: "KIT Data Manager", - // valueRegex: /KIT Data Manager/ - // }, - // { - // keyTitle: "Description", - // keyTooltip: "The description of the dataset.", - // keyLink: "https://schema.org/description", - // value: "The KIT Data Manager is a software for managing research data.", - // valueRegex: /The KIT Data Manager is a software for managing research data./ - // }, - // { - // keyTitle: "Identifier", - // keyTooltip: "The identifier of the dataset.", - // keyLink: "https://schema.org/identifier", - // value: "https://doi.org/10.5445/IR/1000123456", - // valueRegex: /https:\/\/doi.org\/10.5445\/IR\/1000123456/ - // }, - // { - // keyTitle: "Publisher", - // keyTooltip: "The publisher of the dataset.", - // keyLink: "https://schema.org/publisher", - // value: "Karlsruhe Institute of Technology (KIT)", - // valueRegex: /Karlsruhe Institute of Technology \(KIT\)/ - // }, - // { - // keyTitle: "Creator", - // keyTooltip: "The creator of the dataset.", - // keyLink: "https://schema.org/creator", - // value: "Karlsruhe Institute of Technology (KIT)", - // valueRegex: /Karlsruhe Institute of Technology \(KIT\)/ - // }, - // { - // keyTitle: "Contributor", - // keyTooltip: "The contributor of the dataset.", - // keyLink: "https://schema.org/contributor", - // value: "Karlsruhe Institute of Technology (KIT)", - // valueRegex: /Karlsruhe Institute of Technology \(KIT\)/ - // }, - // { - // keyTitle: "Date Published", - // keyTooltip: "The date the dataset was published.", - // keyLink: "https://schema.org/datePublished", - // value: "2021-01-01", - // valueRegex: /2021-01-01/ - // }, - // { - // keyTitle: "Date Modified", - // keyTooltip: "The date the dataset was modified.", - // keyLink: "https://schema.org/dateModified", - // value: "2021-01-01", - // valueRegex: /2021-01-01/ - // }, - // { - // keyTitle: "License", - // keyTooltip: "The license of the dataset.", - // keyLink: "https://schema.org/license", - // value: "https://creativecommons.org/licenses/by/4.0/", - // valueRegex: /https:\/\/creativecommons.org\/licenses\/by\/4.0\// - // } - ] + @Prop() items: FoldableItem[] = [] - @Prop() actions: FoldableAction[] = [ - // { - // title: "View on FAIR Data Point", - // link: "https://kit-fairdatapoint.esc.rzg.mpg.de/fdp/dataset/kitdm/", - // style: "primary" - // }, - // { - // title: "View on FAIR Data Point", - // link: "https://kit-fairdatapoint.esc.rzg.mpg.de/fdp/dataset/kitdm/", - // style: "secondary" - // }, - // { - // title: "View on FAIR Data Point", - // link: "https://kit-fairdatapoint.esc.rzg.mpg.de/fdp/dataset/kitdm/", - // style: "danger" - // } - ] + @Prop() actions: FoldableAction[] = [] /** * The private state of whether the subcomponents in the table should be loaded. @@ -138,7 +59,7 @@ export class FoldableComponent { @Prop() showSubcomponents: boolean = true; private toggleSubcomponents = () => { - console.log(`currentLevelOfSubcomponents: ${this.currentLevelOfSubcomponents}, levelOfSubcomponents: ${this.levelOfSubcomponents}, showSubcomponents: ${this.showSubcomponents}`); + // console.log(`currentLevelOfSubcomponents: ${this.currentLevelOfSubcomponents}, levelOfSubcomponents: ${this.levelOfSubcomponents}, showSubcomponents: ${this.showSubcomponents}`); if (this.showSubcomponents && this.levelOfSubcomponents - this.currentLevelOfSubcomponents > 0) this.loadSubcomponents = !this.loadSubcomponents; } @@ -165,22 +86,21 @@ export class FoldableComponent { this.items.length === 0 && this.actions.length === 0 ?
- {/**/} - +
:
- - {/**/} + + {/**/} { this.items.length > 0 ?
+ class="divide-y text-sm leading-6 bg-gray-100 m-1 p-0.5 max-h-72 overflow-y-scroll border rounded"> @@ -189,7 +109,7 @@ export class FoldableComponent { + class="bg-grey-100 flex flex-col items-center justify-between overflow-y-scroll w-full max-h-64 rounded-b"> { this.items.map((value) => { return ( @@ -221,7 +141,15 @@ export class FoldableComponent {
- {/*{value.value}*/} + {/*{*/} + {/* this.loadSubcomponents && !value.valueIsFoldable ?*/} + {/* */} + {/* : value.value*/} + {/*}*/} + { PID.isPID(value.value) ? (this.loadSubcomponents ? @@ -244,6 +172,7 @@ export class FoldableComponent { : "" } + {/**/} { this.actions.length > 0 ? diff --git a/src/components/foldable-component/readme.md b/src/components/foldable-component/readme.md index bfdc956..248cf44 100644 --- a/src/components/foldable-component/readme.md +++ b/src/components/foldable-component/readme.md @@ -7,22 +7,21 @@ ## Properties -| Property | Attribute | Description | Type | Default | -| ----------------------------- | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `actions` | -- | | `FoldableAction[]` | `[ // { // title: "View on FAIR Data Point", // link: "https://kit-fairdatapoint.esc.rzg.mpg.de/fdp/dataset/kitdm/", // style: "primary" // }, // { // title: "View on FAIR Data Point", // link: "https://kit-fairdatapoint.esc.rzg.mpg.de/fdp/dataset/kitdm/", // style: "secondary" // }, // { // title: "View on FAIR Data Point", // link: "https://kit-fairdatapoint.esc.rzg.mpg.de/fdp/dataset/kitdm/", // style: "danger" // } ]` | -| `changingColors` | `changing-colors` | Should the table inside the component change colors every other line? | `boolean` | `true` | -| `currentLevelOfSubcomponents` | `current-level-of-subcomponents` | The current elevation level of the subcomponents. If the difference between the current level and the level of the subcomponents is 0, the subcomponents are not shown. | `number` | `0` | -| `items` | -- | | `FoldableItem[]` | `[ // { // keyTitle: "Title", // keyTooltip: "The title of the dataset.", // keyLink: "https://schema.org/name", // value: "KIT Data Manager", // valueRegex: /KIT Data Manager/ // }, // { // keyTitle: "Description", // keyTooltip: "The description of the dataset.", // keyLink: "https://schema.org/description", // value: "The KIT Data Manager is a software for managing research data.", // valueRegex: /The KIT Data Manager is a software for managing research data./ // }, // { // keyTitle: "Identifier", // keyTooltip: "The identifier of the dataset.", // keyLink: "https://schema.org/identifier", // value: "https://doi.org/10.5445/IR/1000123456", // valueRegex: /https:\/\/doi.org\/10.5445\/IR\/1000123456/ // }, // { // keyTitle: "Publisher", // keyTooltip: "The publisher of the dataset.", // keyLink: "https://schema.org/publisher", // value: "Karlsruhe Institute of Technology (KIT)", // valueRegex: /Karlsruhe Institute of Technology \(KIT\)/ // }, // { // keyTitle: "Creator", // keyTooltip: "The creator of the dataset.", // keyLink: "https://schema.org/creator", // value: "Karlsruhe Institute of Technology (KIT)", // valueRegex: /Karlsruhe Institute of Technology \(KIT\)/ // }, // { // keyTitle: "Contributor", // keyTooltip: "The contributor of the dataset.", // keyLink: "https://schema.org/contributor", // value: "Karlsruhe Institute of Technology (KIT)", // valueRegex: /Karlsruhe Institute of Technology \(KIT\)/ // }, // { // keyTitle: "Date Published", // keyTooltip: "The date the dataset was published.", // keyLink: "https://schema.org/datePublished", // value: "2021-01-01", // valueRegex: /2021-01-01/ // }, // { // keyTitle: "Date Modified", // keyTooltip: "The date the dataset was modified.", // keyLink: "https://schema.org/dateModified", // value: "2021-01-01", // valueRegex: /2021-01-01/ // }, // { // keyTitle: "License", // keyTooltip: "The license of the dataset.", // keyLink: "https://schema.org/license", // value: "https://creativecommons.org/licenses/by/4.0/", // valueRegex: /https:\/\/creativecommons.org\/licenses\/by\/4.0\// // } ]` | -| `levelOfSubcomponents` | `level-of-subcomponents` | The maximum level of subcomponents to show. | `number` | `1` | -| `openStatus` | `open-status` | Should the details element be open by default? | `boolean` | `false` | -| `showSubcomponents` | `show-subcomponents` | Should the subcomponents be shown? | `boolean` | `true` | +| Property | Attribute | Description | Type | Default | +| ----------------------------- | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | ------- | +| `actions` | -- | | `FoldableAction[]` | `[]` | +| `changingColors` | `changing-colors` | Should the table inside the component change colors every other line? | `boolean` | `true` | +| `currentLevelOfSubcomponents` | `current-level-of-subcomponents` | The current elevation level of the subcomponents. If the difference between the current level and the level of the subcomponents is 0, the subcomponents are not shown. | `number` | `0` | +| `items` | -- | | `FoldableItem[]` | `[]` | +| `levelOfSubcomponents` | `level-of-subcomponents` | The maximum level of subcomponents to show. | `number` | `1` | +| `openStatus` | `open-status` | Should the details element be open by default? | `boolean` | `false` | +| `showSubcomponents` | `show-subcomponents` | Should the subcomponents be shown? | `boolean` | `true` | ## Dependencies ### Used by - - [display-magic](../display-magic) - [intelligent-handle](../intelligent-handle) - [useful-orcid](../useful-orcid) @@ -37,7 +36,6 @@ graph TD; foldable-component --> intelligent-handle foldable-component --> handle-highlight intelligent-handle --> foldable-component - display-magic --> foldable-component useful-orcid --> foldable-component style foldable-component fill:#f9f,stroke:#333,stroke-width:4px ``` diff --git a/src/utils/DateType.tsx b/src/utils/DateType.tsx new file mode 100644 index 0000000..fab4bba --- /dev/null +++ b/src/utils/DateType.tsx @@ -0,0 +1,36 @@ +import {GenericIdentifierType} from "./GenericIdentifierType"; +import {FunctionalComponent, h} from "@stencil/core"; + +export class DateType extends GenericIdentifierType{ + + private _date: Date; + + getSettingsKey(): string { + return "DateType"; + } + + hasCorrectFormat(): boolean { + const regex = new RegExp('^([0-9]{4})-([0]?[1-9]|1[0-2])-([0-2][0-9]|3[0-1])(T([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9](.[0-9]*)?(Z|([+|-]([0-1][0-9]|2[0-3]):[0-5][0-9])){1}))$') + return regex.test(this.value) + } + + init(): Promise { + this._date = new Date(this.value); + return Promise.resolve(undefined); + } + + isResolvable(): boolean { + return false; + } + + renderBody(): FunctionalComponent { + return undefined; + } + + renderPreview(): FunctionalComponent { + return ( + {this._date.toLocaleString()} + ) + } + +} diff --git a/src/utils/FallbackType.tsx b/src/utils/FallbackType.tsx index 56b9d65..0d8944f 100644 --- a/src/utils/FallbackType.tsx +++ b/src/utils/FallbackType.tsx @@ -3,30 +3,25 @@ import {GenericIdentifierType} from "./GenericIdentifierType"; export class FallbackType extends GenericIdentifierType { hasCorrectFormat(): boolean { - console.log("Fallback has correct format: " + this.value); return true; } init(): Promise { - console.log("Fallback init"); return Promise.resolve(undefined); } isResolvable(): boolean { - console.log("Fallback isn`t resolvable: " + this.value); return false; } renderBody(): FunctionalComponent { - return ( - Body: {this.value} {this.settings} - ) + return undefined; } renderPreview(): FunctionalComponent { return ( - Preview: {this.value} {this.settings} - ) + {this.value} + ) } getSettingsKey(): string { diff --git a/src/utils/FoldableItem.ts b/src/utils/FoldableItem.ts index 6dba884..8e5b52a 100644 --- a/src/utils/FoldableItem.ts +++ b/src/utils/FoldableItem.ts @@ -1,3 +1,5 @@ +import {Parser} from "./Parser"; + export class FoldableItem { private readonly _priority: number; private readonly _keyTitle: string; @@ -6,14 +8,18 @@ export class FoldableItem { private readonly _keyTooltip?: string; private readonly _keyLink?: string; private readonly _valueRegex?: RegExp; + private readonly _doNOTFold?: boolean = true; + private _estimatedTypePriority: number = 0; - constructor(priority: number, keyTitle: string, value: string, keyTooltip?: string, keyLink?: string, valueRegex?: RegExp) { + constructor(priority: number, keyTitle: string, value: string, keyTooltip?: string, keyLink?: string, valueRegex?: RegExp, valueIsFoldable?: boolean) { this._priority = priority; this._keyTitle = keyTitle; this._value = value; this._keyTooltip = keyTooltip; this._keyLink = keyLink; this._valueRegex = valueRegex; + this._doNOTFold = valueIsFoldable; + this._estimatedTypePriority = Parser.getEstimatedPriority(this._value); } get priority(): number { @@ -40,6 +46,14 @@ export class FoldableItem { return this._valueRegex; } + get doNOTFold(): boolean { + return this._doNOTFold; + } + + get estimatedTypePriority(): number { + return this._estimatedTypePriority; + } + isValidValue(): boolean { return this._valueRegex.test(this._value); } diff --git a/src/utils/ORCIDInfo.ts b/src/utils/ORCIDInfo.ts index ff8b5c1..7a1fede 100644 --- a/src/utils/ORCIDInfo.ts +++ b/src/utils/ORCIDInfo.ts @@ -274,7 +274,7 @@ export class ORCIDInfo { * @param text The string to check. */ static isORCiD(text: string): boolean { - return text.match("^[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{3}[0-9X]$") !== null; + return text.match("^(https:\/\/orcid.org\/)?[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{3}[0-9X]$") !== null; } /** @@ -284,6 +284,8 @@ export class ORCIDInfo { static async getORCiDInfo(orcid: string): Promise { if (!ORCIDInfo.isORCiD(orcid)) throw new Error("Invalid input"); + if (orcid.match("^(https:\/\/orcid.org\/)?[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{3}[0-9X]$") !== null) orcid = orcid.replace("https://orcid.org/", ""); + console.log("Fetching ORCID data for " + orcid); const response = await fetch(`https://pub.orcid.org/v3.0/${orcid}`, { headers: { @@ -305,21 +307,23 @@ export class ORCIDInfo { organization: string, department: string, }[] = []; - for (let i = 0; i < affiliations.length; i++) { - const employmentSummary = affiliations[i]["summaries"][0]["employment-summary"]; - let employment = { - startDate: new Date(), - endDate: null, - organization: null, - department: null + try { + for (let i = 0; i < affiliations.length; i++) { + const employmentSummary = affiliations[i]["summaries"][0]["employment-summary"]; + let employment = { + startDate: new Date(), + endDate: null, + organization: null, + department: null + } + if (employmentSummary["start-date"] !== null) employment.startDate = new Date(employmentSummary["start-date"]["year"]["value"], employmentSummary["start-date"]["month"]["value"], employmentSummary["start-date"]["day"]["value"]); + if (employmentSummary["end-date"] !== null) employment.endDate = new Date(employmentSummary["end-date"]["year"]["value"], employmentSummary["end-date"]["month"]["value"], employmentSummary["end-date"]["day"]["value"]); + employment.organization = employmentSummary["organization"]["name"]; + employment.department = employmentSummary["department-name"]; + + employments.push(employment); } - if (employmentSummary["start-date"] !== null) employment.startDate = new Date(employmentSummary["start-date"]["year"]["value"], employmentSummary["start-date"]["month"]["value"], employmentSummary["start-date"]["day"]["value"]); - if (employmentSummary["end-date"] !== null) employment.endDate = new Date(employmentSummary["end-date"]["year"]["value"], employmentSummary["end-date"]["month"]["value"], employmentSummary["end-date"]["day"]["value"]); - employment.organization = employmentSummary["organization"]["name"]; - employment.department = employmentSummary["department-name"]; - - employments.push(employment); - } + } catch (e) {} // Parse preferred locale, if available let preferredLocale: string | undefined = rawOrcidJSON["preferences"]["locale"] !== null ? rawOrcidJSON["preferences"]["locale"] : undefined; diff --git a/src/utils/ORCIDType.tsx b/src/utils/ORCIDType.tsx index d31432f..b3fa77e 100644 --- a/src/utils/ORCIDType.tsx +++ b/src/utils/ORCIDType.tsx @@ -21,12 +21,22 @@ export class ORCIDType extends GenericIdentifierType { // Generate items and actions this.items.push(...[ - new FoldableItem(0, "ORCiD", parsed.orcid, "ORCiD is a free service for researchers to distinguish themselves by creating a unique personal identifier.", "https://orcid.org"), - new FoldableItem(0, "Family Name", parsed.familyName, "The family name of the person."), - new FoldableItem(0, "Given Names", parsed.givenNames.toString(), "The given names of the person."), - new FoldableItem(0, "Current Affiliation", parsed.getAffiliationAtString(new Date(Date.now()), true), "The current affiliation of the person."), + new FoldableItem(0, "ORCiD", parsed.orcid, "ORCiD is a free service for researchers to distinguish themselves by creating a unique personal identifier.", "https://orcid.org",undefined, true), + new FoldableItem(1, "Family Name", parsed.familyName, "The family name of the person."), + new FoldableItem(2, "Given Names", parsed.givenNames.toString(), "The given names of the person."), ]) + this.actions.push(new FoldableAction(0, "Open ORCiD", `https://orcid.org/${parsed.orcid}`, "primary")) + + try { + const affiliation = parsed.getAffiliationAtString(new Date(Date.now()), true) + if (affiliation !== undefined && affiliation.length > 2 )this.items.push( + new FoldableItem(50, "Current Affiliation", affiliation, "The current affiliation of the person."), + ) + } catch (e) { + console.log(e); + } + // if (parsed.getAffiliationAt(this.affiliationAt) !== parsed.getAffiliationAt(new Date(Date.now()))) { // this.items.push({ // keyTitle: "Affiliation at " + this.affiliationAt.toLocaleDateString("en-US", { @@ -45,24 +55,24 @@ export class ORCIDType extends GenericIdentifierType { // If there is a primary e-mail address, generate an item and an action to send email if (primary) { - this.items.push(new FoldableItem(0, "Primary E-Mail address", primary.email, "The primary e-mail address of the person.")) + this.items.push(new FoldableItem(20, "Primary E-Mail address", primary.email, "The primary e-mail address of the person.")) this.actions.push(new FoldableAction(0, "Send E-Mail", `mailto:${primary.email}`, "secondary")) } // If there are other e-mail addresses, generate an item with a list of them - if (other.length > 0) this.items.push(new FoldableItem(0, "Other E-Mail addresses", other.map((email) => email.email).join(", "), "All other e-mail addresses of the person.")) + if (other.length > 0) this.items.push(new FoldableItem(70, "Other E-Mail addresses", other.map((email) => email.email).join(", "), "All other e-mail addresses of the person.")) - if (parsed.preferredLocale) this.items.push(new FoldableItem(0, "Preferred Language", getLocaleDetail(parsed.preferredLocale, "language"), "The preferred locale/language of the person.")) + if (parsed.preferredLocale) this.items.push(new FoldableItem(25, "Preferred Language", getLocaleDetail(parsed.preferredLocale, "language"), "The preferred locale/language of the person.")) for (let url of parsed.researcherUrls) { - this.items.push(new FoldableItem(0, url.name, url.url, "A link to a website specified by the person.")) + this.items.push(new FoldableItem(100, url.name, url.url, "A link to a website specified by the person.")) } - if (parsed.keywords.length > 0) this.items.push(new FoldableItem(0, "Keywords", parsed.keywords.map((keyword) => keyword.content).join(", "), "Keywords specified by the person.")) + if (parsed.keywords.length > 50) this.items.push(new FoldableItem(60, "Keywords", parsed.keywords.map((keyword) => keyword.content).join(", "), "Keywords specified by the person.")) - if (parsed.biography) this.items.push(new FoldableItem(0, "Biography", parsed.biography, "The biography of the person.")) + if (parsed.biography) this.items.push(new FoldableItem(200, "Biography", parsed.biography, "The biography of the person.")) - if (parsed.country) this.items.push(new FoldableItem(0, "Country", getLocaleDetail(parsed.country, "region"), "The country of the person.")) + if (parsed.country) this.items.push(new FoldableItem(30, "Country", getLocaleDetail(parsed.country, "region"), "The country of the person.")) console.log(this._orcidInfo); console.log(this.items); diff --git a/src/utils/Parser.ts b/src/utils/Parser.ts index 0822653..d153d26 100644 --- a/src/utils/Parser.ts +++ b/src/utils/Parser.ts @@ -2,17 +2,31 @@ import {GenericIdentifierType} from "./GenericIdentifierType"; import {HandleType} from "./HandleType"; import {FallbackType} from "./FallbackType"; import {ORCIDType} from "./ORCIDType"; +import {DateType} from "./DateType"; export class Parser { private static readonly _dataTypes: (new(value: string, settings?: { name: string, value: any }[]) => GenericIdentifierType)[] = [ + DateType, ORCIDType, HandleType, FallbackType, ]; + static getEstimatedPriority(value: string): number { + let priority = 0; + for (let i = 0; i < this._dataTypes.length; i++) { + const obj = new this._dataTypes[i](value); + if (obj.hasCorrectFormat()) { + priority = i; + break; + } + } + return priority; + } + static async getBestFit(value: string, settings: { type: string, values: { name: string, diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 58bbba3..504b373 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -20,8 +20,6 @@ export const handleMap: Map = new Map(); export const unresolvables: Set = new Set(); export function getLocaleDetail(locale: string, type: "region" | "language"): string { - console.log("getLocaleDetail", locale, type); - const friendlyName = new Intl.DisplayNames(['en'], {type: type}).of(locale.toUpperCase()); if (type === "language") return friendlyName; diff --git a/vscode-data.json b/vscode-data.json index dc4d5d8..a6d29dc 100644 --- a/vscode-data.json +++ b/vscode-data.json @@ -33,6 +33,10 @@ "value": "" }, "attributes": [ + { + "name": "amount-of-items", + "description": "" + }, { "name": "changing-colors", "description": "" @@ -49,6 +53,10 @@ "name": "open-status", "description": "" }, + { + "name": "show-subcomponents", + "description": "" + }, { "name": "value", "description": "" From 87368836d8a91d6e59101b42223783c97474a893 Mon Sep 17 00:00:00 2001 From: Maximilian Inckmann - KIT Date: Mon, 14 Aug 2023 10:17:42 +0200 Subject: [PATCH 03/11] Added settings pass through --- src/components.d.ts | 16 +---- .../display-magic/display-magic.stories.ts | 4 +- .../display-magic/display-magic.tsx | 36 +++++++----- src/components/display-magic/readme.md | 20 +++---- src/utils/ORCIDType.tsx | 58 +++++++++++++------ src/utils/Parser.ts | 48 +++++++-------- vscode-data.json | 4 ++ 7 files changed, 102 insertions(+), 84 deletions(-) diff --git a/src/components.d.ts b/src/components.d.ts index a15149e..fcdffbf 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -41,13 +41,7 @@ export namespace Components { "currentLevelOfSubcomponents": number; "levelOfSubcomponents": number; "openStatus": boolean; - "settings": { - type: string, - values: { - name: string, - value: any - }[] - }[]; + "settings": string; "showSubcomponents": boolean; "value": string; } @@ -239,13 +233,7 @@ declare namespace LocalJSX { "currentLevelOfSubcomponents"?: number; "levelOfSubcomponents"?: number; "openStatus"?: boolean; - "settings"?: { - type: string, - values: { - name: string, - value: any - }[] - }[]; + "settings"?: string; "showSubcomponents"?: boolean; "value"?: string; } diff --git a/src/components/display-magic/display-magic.stories.ts b/src/components/display-magic/display-magic.stories.ts index ee87995..8a79efb 100644 --- a/src/components/display-magic/display-magic.stories.ts +++ b/src/components/display-magic/display-magic.stories.ts @@ -16,7 +16,7 @@ const meta: Meta = { settings: { description: "The settings to use for the component", control: { - type: "object", + type: "text", } }, changingColors: { @@ -65,7 +65,7 @@ const meta: Meta = { }, args: { value: "21.11152/B88E78D4-E1EE-40F7-96CE-EC1AFCFF6343", - settings: {}, + settings: '[{"type":"ORCIDConfig","values":[{"name":"showAffiliation","value":true},{"name":"showOrcid","value":true}]}]', changingColors: true, openStatus: false, amountOfItems: 10, diff --git a/src/components/display-magic/display-magic.tsx b/src/components/display-magic/display-magic.tsx index f65d67a..f4a748c 100644 --- a/src/components/display-magic/display-magic.tsx +++ b/src/components/display-magic/display-magic.tsx @@ -12,13 +12,7 @@ import {Parser} from "../../utils/Parser"; export class DisplayMagic { @Prop() value: string; - @Prop() settings: { - type: string, - values: { - name: string, - value: any - }[] - }[]; + @Prop() settings: string; @Prop() openStatus: boolean = false; @Prop() changingColors: boolean = true; @Prop() amountOfItems: number = 10; @@ -34,10 +28,23 @@ export class DisplayMagic { @State() tablePage: number = 0; async connectedCallback() { - const obj = await Parser.getBestFit(this.value, this.settings); + let settings: { + type: string, + values: { + name: string, + value: any + }[] + }[]; + + try { + settings = JSON.parse(this.settings); + } catch (e) { + } + + const obj = await Parser.getBestFit(this.value, settings); this.identifierObject = obj; - if(this.showSubcomponents) { + if (this.showSubcomponents) { this.items = obj.items; this.items.sort((a, b) => { if (a.priority > b.priority) return 1; @@ -173,7 +180,8 @@ export class DisplayMagic {
-
+
{/*
*/} {/* Previous*/} @@ -186,7 +194,8 @@ export class DisplayMagic { Showing {1 + this.tablePage * this.amountOfItems} to - {this.tablePage * this.amountOfItems + this.amountOfItems - 1} + {this.tablePage * this.amountOfItems + this.amountOfItems - 1} of {this.items.length} entries @@ -217,8 +226,9 @@ export class DisplayMagic { class="relative inline-flex items-center px-4 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-20 focus:outline-offset-0">9 10 - this.tablePage = Math.min(this.tablePage + 1, Math.floor(this.items.length / this.amountOfItems))} - class="relative inline-flex items-center rounded-r-md px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-20 focus:outline-offset-0"> + this.tablePage = Math.min(this.tablePage + 1, Math.floor(this.items.length / this.amountOfItems))} + class="relative inline-flex items-center rounded-r-md px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-20 focus:outline-offset-0"> Next {this.orcidInfo.familyName}, {this.orcidInfo.givenNames} - {this.orcidInfo.getAffiliationAt(this.affiliationAt) !== undefined && this.showAffiliation - ? ` (${this.orcidInfo.getAffiliationAtString(this.affiliationAt, this.showDepartment)}${this.showOrcid ? ", " : ""}` + {this.orcidInfo.getAffiliationsAt(this.affiliationAt) !== undefined && this.showAffiliation + ? ` (${this.orcidInfo.getAffiliationAsString(this.orcidInfo.getAffiliationsAt(this.affiliationAt)[0], this.showDepartment)}${this.showOrcid ? ", " : ""}` : this.showOrcid ? " (" : ""} {this.showOrcid ? {this.orcidInfo.orcid} : ""} - {(this.orcidInfo.getAffiliationAt(this.affiliationAt) !== undefined && this.showAffiliation) || this.showOrcid ? ")" : ""} + {(this.orcidInfo.getAffiliationAsString(this.orcidInfo.getAffiliationsAt(this.affiliationAt)[0]) !== undefined && this.showAffiliation) || this.showOrcid ? ")" : ""} : "" } diff --git a/src/components/display-magic/display-magic.stories.ts b/src/components/display-magic/display-magic.stories.ts index 8a79efb..d6fcf05 100644 --- a/src/components/display-magic/display-magic.stories.ts +++ b/src/components/display-magic/display-magic.stories.ts @@ -65,7 +65,7 @@ const meta: Meta = { }, args: { value: "21.11152/B88E78D4-E1EE-40F7-96CE-EC1AFCFF6343", - settings: '[{"type":"ORCIDConfig","values":[{"name":"showAffiliation","value":true},{"name":"showOrcid","value":true}]}]', + settings: '[]', changingColors: true, openStatus: false, amountOfItems: 10, @@ -118,6 +118,7 @@ export const Fallback: Story = { export const ORCIDInRecord = { args: { value: "21.T11981/be908bd1-e049-4d35-975e-8e27d40117e6", + openStatus: true, } } @@ -125,6 +126,14 @@ export const ORCIDInRecordWithoutLimit = { args: { value: "21.T11981/be908bd1-e049-4d35-975e-8e27d40117e6", amountOfItems: 100, + openStatus: true, + } +} + +export const ORCIDInRecordWithSettings = { + args: { + value: "21.T11981/be908bd1-e049-4d35-975e-8e27d40117e6", + settings: '[{"type":"ORCIDConfig","values":[{"name":"affiliationAt","value":949363200000}]}]', } } diff --git a/src/components/display-magic/display-magic.tsx b/src/components/display-magic/display-magic.tsx index f4a748c..c608745 100644 --- a/src/components/display-magic/display-magic.tsx +++ b/src/components/display-magic/display-magic.tsx @@ -1,4 +1,4 @@ -import {Component, Host, h, Prop, State} from '@stencil/core'; +import {Component, Host, h, Prop, State, Watch} from '@stencil/core'; import {GenericIdentifierType} from "../../utils/GenericIdentifierType"; import {FoldableItem} from "../../utils/FoldableItem"; import {FoldableAction} from "../../utils/FoldableAction"; @@ -27,6 +27,14 @@ export class DisplayMagic { @State() displayStatus: "loading" | "loaded" | "error" = "loading"; @State() tablePage: number = 0; + // reload and rerender the component when the value changes + @Watch("value") + watchValue(newValue: string, oldValue: string) { + console.log(`value changed from ${oldValue} to ${newValue}`); + this.displayStatus = "loading"; + this.connectedCallback().then(r => console.log("done", r)); + } + async connectedCallback() { let settings: { type: string, @@ -81,7 +89,7 @@ export class DisplayMagic { render() { return ( - + { this.items.length === 0 && this.actions.length === 0 ? this.identifierObject !== undefined @@ -95,13 +103,8 @@ export class DisplayMagic { Loading... {this.value} - - //
- // {this.identifierObject !== undefined ? this.identifierObject.renderPreview() : this.value} - //
:
@@ -112,7 +115,7 @@ export class DisplayMagic { ?
- +
@@ -122,8 +125,10 @@ export class DisplayMagic { { - this.items.map((value, index) => { - if (index >= this.amountOfItems) return; + this.items.filter((_, index) => { + // Filter out items that are not on the current page + return index >= this.tablePage * this.amountOfItems && index < this.tablePage * this.amountOfItems + this.amountOfItems; + }).map((value) => { return (
Key
@@ -162,13 +167,14 @@ export class DisplayMagic { levelOfSubcomponents={this.levelOfSubcomponents} currentLevelOfSubcomponents={this.currentLevelOfSubcomponents + 1} amountOfItems={this.amountOfItems} - showSubcomponents={true} + showSubcomponents={true} settings={this.settings} /> : this.showSubcomponents && this.currentLevelOfSubcomponents === this.levelOfSubcomponents && !value.doNOTFold ? : value.value } @@ -181,62 +187,58 @@ export class DisplayMagic {
- {/*
*/} - {/* Previous*/} - {/* Next*/} - {/*
*/} -