From 9018fc143e84640da1259563a92eed7c0c164782 Mon Sep 17 00:00:00 2001 From: Andrey Sobolev Date: Wed, 8 Dec 2021 16:09:51 +0700 Subject: [PATCH] Fix #575 (#576) Signed-off-by: Andrey Sobolev --- packages/ui/src/components/Component.svelte | 7 +- packages/ui/src/components/ErrorPopup.svelte | 28 +++ .../ui/src/components/ErrorPresenter.svelte | 32 +++ packages/ui/src/index.ts | 9 +- .../src/components/Table.svelte | 31 ++- .../src/components/TableView.svelte | 216 +++++++++++------- plugins/view-resources/src/utils.ts | 47 ++-- plugins/view/src/index.ts | 12 +- 8 files changed, 252 insertions(+), 130 deletions(-) create mode 100644 packages/ui/src/components/ErrorPopup.svelte create mode 100644 packages/ui/src/components/ErrorPresenter.svelte diff --git a/packages/ui/src/components/Component.svelte b/packages/ui/src/components/Component.svelte index 8722325c05..f9340fd459 100644 --- a/packages/ui/src/components/Component.svelte +++ b/packages/ui/src/components/Component.svelte @@ -20,6 +20,7 @@ // import Icon from './Icon.svelte' import Loading from './Loading.svelte' import ErrorBoundary from './internal/ErrorBoundary' +import ErrorPresenter from './ErrorPresenter.svelte'; export let is: AnyComponent export let props = {} @@ -36,8 +37,8 @@ {:catch err} - ERROR: {console.log(err, JSON.stringify(component))} - {props} - {err} +
+    
+  
{/await} diff --git a/packages/ui/src/components/ErrorPopup.svelte b/packages/ui/src/components/ErrorPopup.svelte new file mode 100644 index 0000000000..1d8b0de2e3 --- /dev/null +++ b/packages/ui/src/components/ErrorPopup.svelte @@ -0,0 +1,28 @@ + + + + +{error.message} +
+  {#if error.status.params}
+    {JSON.stringify(error.status.params, undefined, 2)}
+  {/if}
+
diff --git a/packages/ui/src/components/ErrorPresenter.svelte b/packages/ui/src/components/ErrorPresenter.svelte new file mode 100644 index 0000000000..ad82a257bf --- /dev/null +++ b/packages/ui/src/components/ErrorPresenter.svelte @@ -0,0 +1,32 @@ + + + + + + + + + diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts index 7de0a87889..aa1eb2995a 100644 --- a/packages/ui/src/index.ts +++ b/packages/ui/src/index.ts @@ -15,9 +15,9 @@ import { SvelteComponent } from 'svelte' import type { AnySvelteComponent, AnyComponent, PopupAlignment, LabelAndProps, TooltipAligment } from './types' -import { getResource, IntlString } from '@anticrm/platform' -import { addStringsLoader } from '@anticrm/platform' -import { uiId } from './plugin' +import { getResource, IntlString, addStringsLoader } from '@anticrm/platform' +import { uiId } from './plugin' +import { writable, readable } from 'svelte/store' import Root from './components/internal/Root.svelte' @@ -79,11 +79,10 @@ export { default as IconDelete } from './components/icons/Delete.svelte' export { default as IconEdit } from './components/icons/Edit.svelte' export { default as IconInfo } from './components/icons/Info.svelte' export { default as Menu } from './components/Menu.svelte' +export { default as ErrorPresenter } from './components/ErrorPresenter.svelte' export * from './utils' -import { writable, readable } from 'svelte/store' - export function createApp (target: HTMLElement): SvelteComponent { return new Root({ target }) } diff --git a/plugins/view-resources/src/components/Table.svelte b/plugins/view-resources/src/components/Table.svelte index a01a7f8ba0..aa7fe425cb 100644 --- a/plugins/view-resources/src/components/Table.svelte +++ b/plugins/view-resources/src/components/Table.svelte @@ -15,16 +15,14 @@ --> - -{#await buildModel({client, _class, keys: config, options})} +{#await buildModel({ client, _class, keys: config, options })} {:then model} @@ -100,12 +99,12 @@ {#each model as attribute, cell} {#if !cell} - {:else} - + {/if} {/each} diff --git a/plugins/view-resources/src/components/TableView.svelte b/plugins/view-resources/src/components/TableView.svelte index 98060fa685..0f1eedf0c0 100644 --- a/plugins/view-resources/src/components/TableView.svelte +++ b/plugins/view-resources/src/components/TableView.svelte @@ -13,19 +13,15 @@ // See the License for the specific language governing permissions and // limitations under the License. --> - -{#await buildModel({client, _class, keys: config, options})} - +{#await buildModel({ client, _class, keys: config, options })} + {:then model} -
- -
- +
+
- - - {#each model as attribute, cellHead} - {#if !cellHead} - + + {#if objects} + + {#each objects as object, row (object._id)} + + {#each model as attribute, cell} + {#if !cell} + + + {:else} + + {/if} + {/each} + + {/each} + + {/if} +
-
- +
+ + + + + {#each model as attribute, cellHead} + {#if !cellHead} + + {/if} + + - {/if} - - {/each} - - - {#if objects} - - {#each objects as object, row (object._id)} - - {#each model as attribute, cell} - {#if !cell} - - - {:else} - - {/if} - {/each} - - {/each} - - {/if} -
+
+ +
+
changeSorting(attribute.key)} + > +
+
changeSorting(attribute.key)}> -
-
-
- - -
-
-
+ {/each} +
+ + +
+ + {/await} diff --git a/plugins/view-resources/src/utils.ts b/plugins/view-resources/src/utils.ts index 6feb4abd44..aa2e7a4330 100644 --- a/plugins/view-resources/src/utils.ts +++ b/plugins/view-resources/src/utils.ts @@ -14,37 +14,37 @@ // limitations under the License. // -import core, { Class, Client, Doc, FindOptions, FindResult, Obj, Ref, AttachedDoc, TxOperations, Collection } from '@anticrm/core' +import core, { AttachedDoc, Class, Client, Collection, Doc, FindOptions, FindResult, Obj, Ref, TxOperations } from '@anticrm/core' import type { IntlString } from '@anticrm/platform' import { getResource } from '@anticrm/platform' import { getAttributePresenterClass } from '@anticrm/presentation' -import type { AnyComponent } from '@anticrm/ui' import type { Action, ActionTarget, BuildModelOptions } from '@anticrm/view' -import view, { AttributeModel } from '@anticrm/view' +import view, { AttributeModel, BuildModelKey } from '@anticrm/view' +import { ErrorPresenter } from '@anticrm/ui' /** * @public */ -export async function getObjectPresenter (client: Client, _class: Ref>, preserveKey: string): Promise { +export async function getObjectPresenter (client: Client, _class: Ref>, preserveKey: BuildModelKey): Promise { const clazz = client.getHierarchy().getClass(_class) const presenterMixin = client.getHierarchy().as(clazz, view.mixin.AttributePresenter) if (presenterMixin.presenter === undefined) { if (clazz.extends !== undefined) { return await getObjectPresenter(client, clazz.extends, preserveKey) } else { - throw new Error('object presenter not found for ' + preserveKey) + throw new Error('object presenter not found for ' + JSON.stringify(preserveKey)) } } const presenter = await getResource(presenterMixin.presenter) return { - key: preserveKey, + key: typeof preserveKey === 'string' ? preserveKey : '', _class, label: clazz.label, presenter } } -async function getAttributePresenter (client: Client, _class: Ref>, key: string, preserveKey: string): Promise { +async function getAttributePresenter (client: Client, _class: Ref>, key: string, preserveKey: BuildModelKey): Promise { const attribute = client.getHierarchy().getAttribute(_class, key) let attrClass = getAttributePresenterClass(attribute) const clazz = client.getHierarchy().getClass(attrClass) @@ -57,25 +57,25 @@ async function getAttributePresenter (client: Client, _class: Ref>, k parent = pclazz.extends } if (presenterMixin.presenter === undefined) { - throw new Error('attribute presenter not found for ' + preserveKey) + throw new Error('attribute presenter not found for ' + JSON.stringify(preserveKey)) } const presenter = await getResource(presenterMixin.presenter) return { - key: preserveKey, + key: key, _class: attrClass, label: attribute.label, presenter } } -async function getPresenter (client: Client, _class: Ref>, key: string, preserveKey: string, options?: FindOptions): Promise { +async function getPresenter (client: Client, _class: Ref>, key: BuildModelKey, preserveKey: BuildModelKey, options?: FindOptions): Promise { if (typeof key === 'object') { const { presenter, label } = key return { key: '', _class, label: label as IntlString, - presenter: await getResource(presenter as AnyComponent) + presenter: await getResource(presenter) } } if (key.length === 0) { @@ -103,16 +103,25 @@ async function getPresenter (client: Client, _class: Ref>, key: strin } export async function buildModel (options: BuildModelOptions): Promise { - console.log('building table model for', options._class) + console.log('building table model for', options) // eslint-disable-next-line array-callback-return - const model = options.keys.map(key => { + const model = options.keys.map(async key => { try { - const result = getPresenter(options.client, options._class, key, key, options.options) - return result + return await getPresenter(options.client, options._class, key, key, options.options) } catch (err: any) { - if (!(options.ignoreMissing ?? false)) { - throw err + if ((options.ignoreMissing ?? false)) { + return undefined } + const stringKey = (typeof key === 'string') ? key : key.label + console.error('Failed to find presenter for', key, err) + const errorPresenter: AttributeModel = { + key: '', + presenter: ErrorPresenter, + label: stringKey as IntlString, + _class: core.class.TypeString, + props: { error: err } + } + return errorPresenter } }) console.log(model) @@ -134,7 +143,7 @@ export async function getActions (client: Client, _class: Ref>): Prom return await client.findAll(view.class.Action, { _id: { $in: filterActions(client, _class, targets) } }) } -export async function deleteObject (client: Client & TxOperations, object: Doc) { +export async function deleteObject (client: Client & TxOperations, object: Doc): Promise { const hierarchy = client.getHierarchy() const attributes = hierarchy.getAllAttributes(object._class) for (const [name, attribute] of attributes) { @@ -142,7 +151,7 @@ export async function deleteObject (client: Client & TxOperations, object: Doc) const collection = attribute.type as Collection const allAttached = await client.findAll(collection.of, { attachedTo: object._id }) for (const attached of allAttached) { - deleteObject(client, attached) + deleteObject(client, attached).catch(err => console.log('failed to delete', name, err)) } } } diff --git a/plugins/view/src/index.ts b/plugins/view/src/index.ts index 82c7b6f677..be9680548a 100644 --- a/plugins/view/src/index.ts +++ b/plugins/view/src/index.ts @@ -103,6 +103,14 @@ export interface Sequence extends Doc { */ export const viewId = 'view' as Plugin +/** + * @public + */ +export type BuildModelKey = string | { + presenter: AnyComponent + label: string +} + /** * @public */ @@ -111,6 +119,8 @@ export interface AttributeModel { label: IntlString _class: Ref> presenter: AnySvelteComponent + // Extra properties for component + props?: Record } /** @@ -119,7 +129,7 @@ export interface AttributeModel { export interface BuildModelOptions { client: Client _class: Ref> - keys: string[] + keys: BuildModelKey[] options?: FindOptions ignoreMissing?: boolean }