diff --git a/models/lead/src/index.ts b/models/lead/src/index.ts index d451181794..4d55908a10 100644 --- a/models/lead/src/index.ts +++ b/models/lead/src/index.ts @@ -290,13 +290,8 @@ export function createModel (builder: Builder): void { attachTo: lead.class.Lead, descriptor: view.viewlet.List, configOptions: { - hiddenKeys: ['title'], - sortable: true, - extraProps: { - displayProps: { - optional: true - } - } + strict: true, + hiddenKeys: ['title'] }, config: [ { key: '', displayProps: { fixed: 'left', key: 'lead' } }, @@ -324,10 +319,11 @@ export function createModel (builder: Builder): void { key: '', presenter: tracker.component.RelatedIssueSelector, label: tracker.string.Relations, - displayProps: { fixed: 'left', key: 'issues' } + displayProps: { fixed: 'left', key: 'issues', optional: true } }, - { key: 'attachments', displayProps: { fixed: 'left', key: 'attachments' } }, - { key: 'comments', displayProps: { fixed: 'left', key: 'comments' } }, + { key: 'attachments', displayProps: { key: 'attachments', optional: true } }, + { key: 'comments', displayProps: { key: 'comments', optional: true } }, + { key: '', displayProps: { grow: true } }, { key: '$lookup.attachedTo.$lookup.channels', label: contact.string.ContactInfo, diff --git a/models/recruit/src/index.ts b/models/recruit/src/index.ts index 6aa0fa0ed9..0768571773 100644 --- a/models/recruit/src/index.ts +++ b/models/recruit/src/index.ts @@ -704,6 +704,7 @@ export function createModel (builder: Builder): void { label: tracker.string.Issues, displayProps: { fixed: 'left', key: 'issues' } }, + { key: '', displayProps: { grow: true } }, { key: 'attachments', displayProps: { fixed: 'left', key: 'attachments' } }, { key: 'comments', displayProps: { fixed: 'left', key: 'comments' } }, { @@ -732,13 +733,8 @@ export function createModel (builder: Builder): void { } }, configOptions: { - hiddenKeys: ['name', 'attachedTo'], - sortable: true, - extraProps: { - displayProps: { - optional: true - } - } + strict: true, + hiddenKeys: ['name', 'attachedTo'] }, baseQuery: { doneState: null, diff --git a/models/tracker/src/index.ts b/models/tracker/src/index.ts index 99128087c3..03fd5b0df2 100644 --- a/models/tracker/src/index.ts +++ b/models/tracker/src/index.ts @@ -488,6 +488,7 @@ export function createModel (builder: Builder): void { descriptor: view.viewlet.List, viewOptions: issuesOptions(false), configOptions: { + strict: true, hiddenKeys: [ 'title', 'blockedBy', @@ -503,14 +504,10 @@ export function createModel (builder: Builder): void { 'estimation', 'status', 'dueDate', - 'attachedTo' - ], - sortable: true, - extraProps: { - displayProps: { - optional: true - } - } + 'attachedTo', + 'createdBy', + 'modifiedBy' + ] }, config: [ { @@ -549,6 +546,8 @@ export function createModel (builder: Builder): void { displayProps: { optional: true, compression: true }, props: { kind: 'list', full: false } }, + { key: 'attachments', displayProps: { key: 'attachments', optional: true } }, + { key: 'comments', displayProps: { key: 'comments', optional: true } }, { key: '', label: tracker.string.DueDate, @@ -590,6 +589,7 @@ export function createModel (builder: Builder): void { optional: true } }, + { key: '', displayProps: { grow: true } }, { key: '', label: tracker.string.Estimation, @@ -641,13 +641,18 @@ export function createModel (builder: Builder): void { viewOptions: subIssuesOptions, variant: 'subissue', configOptions: { - sortable: true, - hiddenKeys: ['priority', 'number', 'status', 'title', 'dueDate', 'milestone', 'estimation'], - extraProps: { - displayProps: { - optional: true - } - } + strict: true, + hiddenKeys: [ + 'priority', + 'number', + 'status', + 'title', + 'dueDate', + 'milestone', + 'estimation', + 'createdBy', + 'modifiedBy' + ] }, config: [ { @@ -704,6 +709,7 @@ export function createModel (builder: Builder): void { props: { kind: 'list', size: 'small' }, displayProps: { optional: true } }, + { key: '', displayProps: { grow: true } }, { key: 'modifiedOn', presenter: tracker.component.ModificationDatePresenter, @@ -736,9 +742,8 @@ export function createModel (builder: Builder): void { other: [showColorsViewOption] }, configOptions: { - hiddenKeys: ['milestone', 'estimation', 'component', 'title', 'description'], - extraProps: { displayProps: { optional: true } }, - sortable: true + strict: true, + hiddenKeys: ['milestone', 'estimation', 'component', 'title', 'description', 'createdBy', 'modifiedBy'] }, config: [ // { key: '', presenter: tracker.component.PriorityEditor, props: { kind: 'list', size: 'small' } }, @@ -780,6 +785,7 @@ export function createModel (builder: Builder): void { }, displayProps: { key: 'estimation', optional: true, compression: true } }, + { key: '', displayProps: { grow: true } }, { key: 'modifiedOn', presenter: tracker.component.ModificationDatePresenter, @@ -1885,9 +1891,8 @@ export function createModel (builder: Builder): void { descriptor: view.viewlet.List, viewOptions: milestoneOptions, configOptions: { - hiddenKeys: ['targetDate', 'label', 'description'], - extraProps: { displayProps: { optional: true } }, - sortable: true + strict: true, + hiddenKeys: ['targetDate', 'label', 'description'] }, config: [ { @@ -1895,6 +1900,7 @@ export function createModel (builder: Builder): void { props: { width: '1rem', kind: 'list', size: 'small', justify: 'center' } }, { key: '', presenter: tracker.component.MilestonePresenter, props: { shouldUseMargin: true } }, + { key: '', displayProps: { grow: true } }, { key: '', label: tracker.string.TargetDate, @@ -1966,9 +1972,8 @@ export function createModel (builder: Builder): void { descriptor: view.viewlet.List, viewOptions: componentListViewOptions, configOptions: { - hiddenKeys: ['label', 'description'], - extraProps: { displayProps: { optional: true } }, - sortable: true + strict: true, + hiddenKeys: ['label', 'description'] }, config: [ { @@ -1976,6 +1981,7 @@ export function createModel (builder: Builder): void { presenter: tracker.component.ComponentPresenter, props: { kind: 'list' } }, + { key: '', displayProps: { grow: true } }, { key: '$lookup.lead', presenter: tracker.component.LeadPresenter, diff --git a/plugins/chunter-resources/src/components/CommentsPresenter.svelte b/plugins/chunter-resources/src/components/CommentsPresenter.svelte index 43808bee21..9d11c43df2 100644 --- a/plugins/chunter-resources/src/components/CommentsPresenter.svelte +++ b/plugins/chunter-resources/src/components/CommentsPresenter.svelte @@ -26,7 +26,7 @@ export let withInput: boolean = true -{#if value && value > 0} +{#if (value && value > 0) || withInput}
> icon: Asset | undefined order?: number @@ -62,6 +67,7 @@ function getObjectConfig (_class: Ref>, param: string): AttributeConfig { const clazz = hierarchy.getClass(_class) return { + type: 'attribute', value: param, label: clazz.label, enabled: true, @@ -70,10 +76,11 @@ } } - function getBaseConfig (viewlet: Viewlet): AttributeConfig[] { + function getBaseConfig (viewlet: Viewlet): Config[] { const lookup = buildConfigLookup(hierarchy, viewlet.attachTo, viewlet.config, viewlet.options?.lookup) - const result: AttributeConfig[] = [] + const result: Config[] = [] const clazz = hierarchy.getClass(viewlet.attachTo) + let wasOptional = false for (const param of viewlet.config) { if (typeof param === 'string') { if (viewlet.configOptions?.hiddenKeys?.includes(param)) continue @@ -81,22 +88,38 @@ result.push(getObjectConfig(viewlet.attachTo, param)) } else { result.push({ + type: 'attribute', value: param, enabled: true, label: getKeyLabel(client, viewlet.attachTo, param, lookup), _class: viewlet.attachTo, icon: clazz.icon - }) + } as AttributeConfig) } } else { if (viewlet.configOptions?.hiddenKeys?.includes(param.key)) continue - result.push({ - value: param, - label: param.label ?? getKeyLabel(client, viewlet.attachTo, param.key, lookup), - enabled: true, - _class: viewlet.attachTo, - icon: clazz.icon - }) + if (param.displayProps?.grow === true) { + result.push({ + type: 'divider', + value: param + }) + } else { + if (param.displayProps?.optional === true && !wasOptional) { + wasOptional = true + result.push({ + type: 'divider', + value: '' + }) + } + result.push({ + type: 'attribute', + value: param, + label: param.label ?? getKeyLabel(client, viewlet.attachTo, param.key, lookup), + enabled: true, + _class: viewlet.attachTo, + icon: clazz.icon + } as AttributeConfig) + } } } return result @@ -112,13 +135,14 @@ return name } - function processAttribute (attribute: AnyAttribute, result: AttributeConfig[], useMixinProxy = false): void { + function processAttribute (attribute: AnyAttribute, result: Config[], useMixinProxy = false): void { if (attribute.hidden === true || attribute.label === undefined) return if (viewlet.configOptions?.hiddenKeys?.includes(attribute.name)) return if (hierarchy.isDerived(attribute.type._class, core.class.Collection)) return const value = getValue(attribute.name, attribute.type) for (const res of result) { - const key = typeof res.value === 'string' ? res.value : res.value.key + const key = typeof res.value === 'string' ? res.value : res.value?.key + if (key === undefined) return if (key === attribute.name) return if (key === value) return } @@ -134,7 +158,8 @@ const clazz = hierarchy.getClass(attribute.attributeOf) const extraProps = viewlet.configOptions?.extraProps if (useMixinProxy) { - const newValue = { + const newValue: AttributeConfig = { + type: 'attribute', value: attribute.attributeOf + '.' + attribute.name, label: attribute.label, enabled: false, @@ -145,7 +170,8 @@ result.push(newValue) } } else { - const newValue = { + const newValue: AttributeConfig = { + type: 'attribute', value: extraProps ? { ...extraProps, key: value } : value, label: attribute.label, enabled: false, @@ -158,8 +184,14 @@ } } - function isExist (result: AttributeConfig[], newValue: AttributeConfig): boolean { + function isAttribute (val: Config): val is AttributeConfig { + return val.type === 'attribute' + } + + function isExist (result: Config[], newValue: Config): boolean { for (const res of result) { + if (!isAttribute(res)) continue + if (!isAttribute(newValue)) continue if (res._class !== newValue._class) continue if (typeof res.value === 'string') { if (res.value === newValue.value) return true @@ -168,7 +200,7 @@ return false } - function getConfig (viewlet: Viewlet, preference: ViewletPreference | undefined): AttributeConfig[] { + function getConfig (viewlet: Viewlet, preference: ViewletPreference | undefined): Config[] { const result = getBaseConfig(viewlet) if (viewlet.configOptions?.strict !== true) { @@ -201,7 +233,12 @@ } async function save (): Promise { - const config = items.filter((p) => p.enabled).map((p) => p.value) + const config = items + .filter( + (p) => + p.value !== undefined && (p.type === 'divider' || (p.type === 'attribute' && (p as AttributeConfig).enabled)) + ) + .map((p) => p.value as string | BuildModelKey) if (preference !== undefined) { await client.update(preference, { config @@ -214,23 +251,28 @@ } } - function restoreDefault (): void { - items = getConfig(viewlet, undefined) - save() + async function restoreDefault (): Promise { + if (preference !== undefined) { + await client.remove(preference) + } } - function setStatus (result: AttributeConfig[], preference: ViewletPreference): AttributeConfig[] { + function setStatus (result: Config[], preference: ViewletPreference): Config[] { for (const key of result) { + if (!isAttribute(key)) continue const index = preference.config.findIndex((p) => deepEqual(p, key.value)) key.enabled = index !== -1 key.order = index !== -1 ? index : undefined } - result.sort((a, b) => { - if (a.order === undefined && b.order === undefined) return 0 - if (a.order === undefined) return 1 - if (b.order === undefined) return -1 - return a.order - b.order - }) + if (viewlet.configOptions?.sortable) { + result.sort((a, b) => { + if (!isAttribute(a) || !isAttribute(b)) return 0 + if (a.order === undefined && b.order === undefined) return 0 + if (a.order === undefined) return 1 + if (b.order === undefined) return -1 + return a.order - b.order + }) + } return result } @@ -240,6 +282,8 @@ } function dragOver (e: DragEvent, i: number) { + e.preventDefault() + e.stopPropagation() const s = selected as number if (dragswap(e, i, s)) { ;[items[i], items[s]] = [items[s], items[i]] @@ -258,6 +302,13 @@ return false } + function change (item: Config, value: boolean): void { + if (isAttribute(item)) { + item.enabled = value + save() + } + } + let selected: number | undefined @@ -270,25 +321,34 @@
{#each items as item, i} -
{ - selected = i - }} - on:dragover|preventDefault={(e) => dragOver(e, i)} - on:dragend={dragEnd} - > - { - item.enabled = e.detail - save() + {#if isAttribute(item)} +
{ + if (ev.dataTransfer) { + ev.dataTransfer.effectAllowed = 'move' + ev.dataTransfer.dropEffect = 'move' + } + // ev.preventDefault() + ev.stopPropagation() + selected = i }} - /> -
+ on:dragover|preventDefault={(e) => dragOver(e, i)} + on:dragend={dragEnd} + > + { + change(item, e.detail) + }} + /> +
+ {:else} +
+ {/if} {/each} {/if}
diff --git a/plugins/view-resources/src/components/list/ListItem.svelte b/plugins/view-resources/src/components/list/ListItem.svelte index 26570976da..f96fb254a2 100644 --- a/plugins/view-resources/src/components/list/ListItem.svelte +++ b/plugins/view-resources/src/components/list/ListItem.svelte @@ -83,8 +83,6 @@ onMount(() => { dispatch('on-mount') }) - - $: growBefore = Math.ceil(model.filter((p) => p.displayProps?.optional !== true).length / 2)
{#each model.filter((p) => p.displayProps?.optional) as attributeModel, i} {@const dp = attributeModel.displayProps} @@ -163,29 +161,30 @@ /> {/if} {/each} - {/if} - {#if i !== 0 && displayProps?.dividerBefore === true} - - {/if} - {#if displayProps?.fixed} - + {:else} + {#if i !== 0 && displayProps?.dividerBefore === true} + + {/if} + {#if displayProps?.fixed} + + + + {:else} - - {:else} - + {/if} {/if} {/if} {/if} diff --git a/plugins/view/src/index.ts b/plugins/view/src/index.ts index c2fb2f9cd4..67bb297629 100644 --- a/plugins/view/src/index.ts +++ b/plugins/view/src/index.ts @@ -475,6 +475,7 @@ export interface DisplayProps { fixed?: 'left' | 'right' // using for align items in row optional?: boolean compression?: boolean + grow?: boolean dividerBefore?: boolean // should show divider before }