mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-20 23:32:14 +00:00
Fix Activity icons (#788)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
parent
decf27ef0d
commit
a7fcf166fa
@ -54,7 +54,7 @@ export const DOMAIN_TASK = 'task' as Domain
|
|||||||
export const DOMAIN_STATE = 'state' as Domain
|
export const DOMAIN_STATE = 'state' as Domain
|
||||||
export const DOMAIN_KANBAN = 'kanban' as Domain
|
export const DOMAIN_KANBAN = 'kanban' as Domain
|
||||||
@Model(task.class.State, core.class.Doc, DOMAIN_STATE, [task.interface.DocWithRank])
|
@Model(task.class.State, core.class.Doc, DOMAIN_STATE, [task.interface.DocWithRank])
|
||||||
@UX('State' as IntlString, undefined, undefined, 'rank')
|
@UX('State' as IntlString, task.icon.TaskState, undefined, 'rank')
|
||||||
export class TState extends TDoc implements State {
|
export class TState extends TDoc implements State {
|
||||||
@Prop(TypeString(), 'Title' as IntlString)
|
@Prop(TypeString(), 'Title' as IntlString)
|
||||||
title!: string
|
title!: string
|
||||||
@ -65,7 +65,7 @@ export class TState extends TDoc implements State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Model(task.class.DoneState, core.class.Doc, DOMAIN_STATE, [task.interface.DocWithRank])
|
@Model(task.class.DoneState, core.class.Doc, DOMAIN_STATE, [task.interface.DocWithRank])
|
||||||
@UX('Done' as IntlString, undefined, undefined, 'title')
|
@UX('Done' as IntlString, task.icon.TaskState, undefined, 'title')
|
||||||
export class TDoneState extends TDoc implements DoneState {
|
export class TDoneState extends TDoc implements DoneState {
|
||||||
@Prop(TypeString(), 'Title' as IntlString)
|
@Prop(TypeString(), 'Title' as IntlString)
|
||||||
title!: string
|
title!: string
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
|
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
|
||||||
<symbol id="activity" viewBox="0 0 20 20" width='20' height='20' fill="none">
|
<symbol id="activity" viewBox="0 0 20 20" width='16' height='16' fill="none">
|
||||||
<path d="M6.03772 12.3181L8.532 9.07628L11.3772 11.3112L13.818 8.16095" stroke="white" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" fill='none'/>
|
<path d="M6.03772 12.3181L8.532 9.07628L11.3772 11.3112L13.818 8.16095" stroke="white" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" fill='none'/>
|
||||||
<ellipse cx="16.6632" cy="3.50027" rx="1.60183" ry="1.60183" stroke="white" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
|
<ellipse cx="16.6632" cy="3.50027" rx="1.60183" ry="1.60183" stroke="white" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
<path d="M12.4372 2.6001H6.38078C3.87125 2.6001 2.31519 4.37737 2.31519 6.8869V13.6222C2.31519 16.1318 3.84074 17.9014 6.38078 17.9014H13.5509C16.0604 17.9014 17.6165 16.1318 17.6165 13.6222V7.75647" stroke="white" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
|
<path d="M12.4372 2.6001H6.38078C3.87125 2.6001 2.31519 4.37737 2.31519 6.8869V13.6222C2.31519 16.1318 3.84074 17.9014 6.38078 17.9014H13.5509C16.0604 17.9014 17.6165 16.1318 17.6165 13.6222V7.75647" stroke="white" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
Before Width: | Height: | Size: 770 B After Width: | Height: | Size: 770 B |
@ -18,34 +18,26 @@
|
|||||||
import type { TxViewlet } from '@anticrm/activity'
|
import type { TxViewlet } from '@anticrm/activity'
|
||||||
import activity from '@anticrm/activity'
|
import activity from '@anticrm/activity'
|
||||||
import contact, { EmployeeAccount, formatName } from '@anticrm/contact'
|
import contact, { EmployeeAccount, formatName } from '@anticrm/contact'
|
||||||
import core, { Class, Doc, Ref, TxCUD, TxUpdateDoc } from '@anticrm/core'
|
import { Doc, Ref } from '@anticrm/core'
|
||||||
import { getResource, IntlString } from '@anticrm/platform'
|
import { Asset, getResource } from '@anticrm/platform'
|
||||||
import { getClient } from '@anticrm/presentation'
|
import { getClient } from '@anticrm/presentation'
|
||||||
import {
|
import {
|
||||||
AnyComponent,
|
|
||||||
AnySvelteComponent,
|
|
||||||
Component,
|
Component,
|
||||||
Icon,
|
Icon,
|
||||||
IconEdit,
|
IconEdit,
|
||||||
IconMoreH,
|
IconMoreH,
|
||||||
Label,
|
Label,
|
||||||
Menu,
|
Menu, ShowMore, showPopup,
|
||||||
showPopup,
|
TimeSince
|
||||||
TimeSince,
|
|
||||||
ShowMore
|
|
||||||
} from '@anticrm/ui'
|
} from '@anticrm/ui'
|
||||||
import type { AttributeModel } from '@anticrm/view'
|
import type { AttributeModel } from '@anticrm/view'
|
||||||
import { buildModel, getActions, getObjectPresenter } from '@anticrm/view-resources'
|
import { getActions } from '@anticrm/view-resources'
|
||||||
import { activityKey, ActivityKey, DisplayTx } from '../activity'
|
import { ActivityKey, DisplayTx } from '../activity'
|
||||||
|
import { getValue, TxDisplayViewlet, updateViewlet } from './utils'
|
||||||
|
|
||||||
export let tx: DisplayTx
|
export let tx: DisplayTx
|
||||||
export let viewlets: Map<ActivityKey, TxViewlet>
|
export let viewlets: Map<ActivityKey, TxViewlet>
|
||||||
|
|
||||||
type TxDisplayViewlet =
|
|
||||||
| (Pick<TxViewlet, 'icon' | 'label' | 'display' | 'editable' | 'hideOnRemove'> & {
|
|
||||||
component?: AnyComponent | AnySvelteComponent
|
|
||||||
})
|
|
||||||
| undefined
|
|
||||||
|
|
||||||
let ptx: DisplayTx | undefined
|
let ptx: DisplayTx | undefined
|
||||||
|
|
||||||
@ -53,6 +45,7 @@
|
|||||||
let props: any
|
let props: any
|
||||||
let employee: EmployeeAccount | undefined
|
let employee: EmployeeAccount | undefined
|
||||||
let model: AttributeModel[] = []
|
let model: AttributeModel[] = []
|
||||||
|
let modelIcon: Asset | undefined = undefined
|
||||||
|
|
||||||
let edit = false
|
let edit = false
|
||||||
|
|
||||||
@ -66,43 +59,12 @@
|
|||||||
|
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
|
|
||||||
async function createPseudoViewlet (dtx: DisplayTx, label: string): Promise<TxDisplayViewlet> {
|
$: updateViewlet(client, viewlets, tx).then((result) => {
|
||||||
const doc = dtx.doc
|
|
||||||
if (doc === undefined) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const docClass: Class<Doc> = client.getModel().getObject(doc._class)
|
|
||||||
|
|
||||||
const presenter = await getObjectPresenter(client, doc._class, { key: 'doc-presenter' })
|
|
||||||
if (presenter !== undefined) {
|
|
||||||
return {
|
|
||||||
display: 'inline',
|
|
||||||
icon: docClass.icon ?? activity.icon.Activity,
|
|
||||||
label: (`${label} ` + docClass.label) as IntlString,
|
|
||||||
component: presenter.presenter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function updateViewlet (dtx: DisplayTx): Promise<{ viewlet: TxDisplayViewlet; id: Ref<TxCUD<Doc>> }> {
|
|
||||||
const key = activityKey(dtx.tx.objectClass, dtx.tx._class)
|
|
||||||
let viewlet: TxDisplayViewlet = viewlets.get(key)
|
|
||||||
|
|
||||||
props = { tx: dtx.tx, value: dtx.doc, edit }
|
|
||||||
|
|
||||||
if (viewlet === undefined && dtx.tx._class === core.class.TxCreateDoc) {
|
|
||||||
// Check if we have a class presenter we could have a pseudo viewlet based on class presenter.
|
|
||||||
viewlet = await createPseudoViewlet(dtx, 'created')
|
|
||||||
}
|
|
||||||
if (viewlet === undefined && dtx.tx._class === core.class.TxRemoveDoc) {
|
|
||||||
viewlet = await createPseudoViewlet(dtx, 'deleted')
|
|
||||||
}
|
|
||||||
return { viewlet, id: dtx.tx._id }
|
|
||||||
}
|
|
||||||
|
|
||||||
$: updateViewlet(tx).then((result) => {
|
|
||||||
if (result.id === tx.tx._id) {
|
if (result.id === tx.tx._id) {
|
||||||
viewlet = result.viewlet
|
viewlet = result.viewlet
|
||||||
|
model = result.model
|
||||||
|
modelIcon = result.modelIcon
|
||||||
|
props = { ...result.props, edit }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -112,47 +74,7 @@
|
|||||||
employee = account
|
employee = account
|
||||||
})
|
})
|
||||||
|
|
||||||
$: if (tx.updateTx !== undefined) {
|
|
||||||
const _class = tx.updateTx.objectClass
|
|
||||||
const ops = {
|
|
||||||
client,
|
|
||||||
_class,
|
|
||||||
keys: Object.keys(tx.updateTx.operations).filter((id) => !id.startsWith('$')),
|
|
||||||
ignoreMissing: true
|
|
||||||
}
|
|
||||||
const hiddenAttrs = new Set([...client.getHierarchy().getAllAttributes(_class).entries()]
|
|
||||||
.filter(([, attr]) => attr.hidden === true)
|
|
||||||
.map(([k]) => k))
|
|
||||||
|
|
||||||
buildModel(ops).then((m) => {
|
|
||||||
model = m.filter((x) => !hiddenAttrs.has(x.key))
|
|
||||||
})
|
|
||||||
} else if (tx.mixinTx !== undefined) {
|
|
||||||
const _class = tx.mixinTx.mixin
|
|
||||||
const ops = {
|
|
||||||
client,
|
|
||||||
_class,
|
|
||||||
keys: Object.keys(tx.mixinTx.attributes).filter((id) => !id.startsWith('$')),
|
|
||||||
ignoreMissing: true
|
|
||||||
}
|
|
||||||
const hiddenAttrs = new Set([...client.getHierarchy().getAllAttributes(_class).entries()]
|
|
||||||
.filter(([, attr]) => attr.hidden === true)
|
|
||||||
.map(([k]) => k))
|
|
||||||
|
|
||||||
buildModel(ops).then((m) => {
|
|
||||||
model = m.filter((x) => !hiddenAttrs.has(x.key))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getValue (m: AttributeModel, utx: any): Promise<any> {
|
|
||||||
const val = (utx as any)[m.key]
|
|
||||||
|
|
||||||
if (client.getHierarchy().isDerived(m._class, core.class.Doc) && typeof val === 'string') {
|
|
||||||
// We have an reference, we need to find a real object to pass for presenter
|
|
||||||
return await client.findOne(m._class, { _id: val as Ref<Doc> })
|
|
||||||
}
|
|
||||||
return val
|
|
||||||
}
|
|
||||||
const showMenu = async (ev: MouseEvent): Promise<void> => {
|
const showMenu = async (ev: MouseEvent): Promise<void> => {
|
||||||
const actions = await getActions(client, tx.doc as Doc)
|
const actions = await getActions(client, tx.doc as Doc)
|
||||||
showPopup(
|
showPopup(
|
||||||
@ -192,7 +114,11 @@
|
|||||||
{#if viewlet}
|
{#if viewlet}
|
||||||
<Icon icon={viewlet.icon} size="small" />
|
<Icon icon={viewlet.icon} size="small" />
|
||||||
{:else}
|
{:else}
|
||||||
<Icon icon={activity.icon.Activity} size="small" />
|
{#if viewlet === undefined && model.length > 0}
|
||||||
|
<Icon icon={modelIcon !== undefined ? modelIcon : IconEdit} size="small" />
|
||||||
|
{:else}
|
||||||
|
<Icon icon={activity.icon.Activity} size="small" />
|
||||||
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -226,7 +152,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
{#if viewlet === undefined && model.length > 0 && tx.updateTx}
|
{#if viewlet === undefined && model.length > 0 && tx.updateTx}
|
||||||
{#each model as m}
|
{#each model as m}
|
||||||
{#await getValue(m, tx.updateTx.operations) then value}
|
{#await getValue(client, m, tx.updateTx.operations) then value}
|
||||||
{#if value === null}
|
{#if value === null}
|
||||||
<span>unset <Label label={m.label} /></span>
|
<span>unset <Label label={m.label} /></span>
|
||||||
{:else}
|
{:else}
|
||||||
@ -237,7 +163,7 @@
|
|||||||
{/each}
|
{/each}
|
||||||
{:else if viewlet === undefined && model.length > 0 && tx.mixinTx}
|
{:else if viewlet === undefined && model.length > 0 && tx.mixinTx}
|
||||||
{#each model as m}
|
{#each model as m}
|
||||||
{#await getValue(m, tx.mixinTx.attributes) then value}
|
{#await getValue(client, m, tx.mixinTx.attributes) then value}
|
||||||
{#if value === null}
|
{#if value === null}
|
||||||
<span>unset <Label label={m.label} /></span>
|
<span>unset <Label label={m.label} /></span>
|
||||||
{:else}
|
{:else}
|
||||||
@ -247,13 +173,11 @@
|
|||||||
{/await}
|
{/await}
|
||||||
{/each}
|
{/each}
|
||||||
{:else if viewlet && viewlet.display === 'inline' && viewlet.component}
|
{:else if viewlet && viewlet.display === 'inline' && viewlet.component}
|
||||||
<div>
|
{#if typeof viewlet.component === 'string'}
|
||||||
{#if typeof viewlet.component === 'string'}
|
<Component is={viewlet.component} {props} on:close={onCancelEdit} />
|
||||||
<Component is={viewlet.component} {props} on:close={onCancelEdit} />
|
{:else}
|
||||||
{:else}
|
<svelte:component this={viewlet.component} {...props} on:close={onCancelEdit} />
|
||||||
<svelte:component this={viewlet.component} {...props} on:close={onCancelEdit} />
|
{/if}
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="time"><TimeSince value={tx.tx.modifiedOn} /></div>
|
<div class="time"><TimeSince value={tx.tx.modifiedOn} /></div>
|
||||||
|
135
plugins/activity-resources/src/components/utils.ts
Normal file
135
plugins/activity-resources/src/components/utils.ts
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
import type { TxViewlet } from '@anticrm/activity'
|
||||||
|
import activity from '@anticrm/activity'
|
||||||
|
import core, { Class, Client, Doc, Ref, TxCUD, TxOperations } from '@anticrm/core'
|
||||||
|
import { Asset, IntlString } from '@anticrm/platform'
|
||||||
|
import { AnyComponent, AnySvelteComponent } from '@anticrm/ui'
|
||||||
|
import { AttributeModel } from '@anticrm/view'
|
||||||
|
import { buildModel, getObjectPresenter } from '@anticrm/view-resources'
|
||||||
|
import { ActivityKey, activityKey, DisplayTx } from '../activity'
|
||||||
|
|
||||||
|
export type TxDisplayViewlet =
|
||||||
|
| (Pick<TxViewlet, 'icon' | 'label' | 'display' | 'editable' | 'hideOnRemove'> & {
|
||||||
|
component?: AnyComponent | AnySvelteComponent
|
||||||
|
})
|
||||||
|
| undefined
|
||||||
|
|
||||||
|
async function createPseudoViewlet (
|
||||||
|
client: Client & TxOperations,
|
||||||
|
dtx: DisplayTx,
|
||||||
|
label: string
|
||||||
|
): Promise<TxDisplayViewlet> {
|
||||||
|
const doc = dtx.doc
|
||||||
|
if (doc === undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const docClass: Class<Doc> = client.getModel().getObject(doc._class)
|
||||||
|
|
||||||
|
const presenter = await getObjectPresenter(client, doc._class, { key: 'doc-presenter' })
|
||||||
|
if (presenter !== undefined) {
|
||||||
|
return {
|
||||||
|
display: 'inline',
|
||||||
|
icon: docClass.icon ?? activity.icon.Activity,
|
||||||
|
label: (`${label} ` + docClass.label) as IntlString,
|
||||||
|
component: presenter.presenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function updateViewlet (
|
||||||
|
client: Client & TxOperations,
|
||||||
|
viewlets: Map<ActivityKey, TxViewlet>,
|
||||||
|
dtx: DisplayTx
|
||||||
|
): Promise<{
|
||||||
|
viewlet: TxDisplayViewlet
|
||||||
|
id: Ref<TxCUD<Doc>>
|
||||||
|
model: AttributeModel[]
|
||||||
|
props: any
|
||||||
|
modelIcon: Asset | undefined
|
||||||
|
}> {
|
||||||
|
const key = activityKey(dtx.tx.objectClass, dtx.tx._class)
|
||||||
|
let viewlet: TxDisplayViewlet = viewlets.get(key)
|
||||||
|
|
||||||
|
const props = { tx: dtx.tx, value: dtx.doc, dtx }
|
||||||
|
let model: AttributeModel[] = []
|
||||||
|
let modelIcon: Asset | undefined
|
||||||
|
|
||||||
|
if (viewlet === undefined) {
|
||||||
|
;({ viewlet, model } = await checkInlineViewlets(dtx, viewlet, client, model))
|
||||||
|
if (model !== undefined) {
|
||||||
|
// Check for State attribute
|
||||||
|
for (const a of model) {
|
||||||
|
if (a.icon !== undefined) {
|
||||||
|
modelIcon = a.icon
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { viewlet, id: dtx.tx._id, model, props, modelIcon }
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkInlineViewlets (
|
||||||
|
dtx: DisplayTx,
|
||||||
|
viewlet: TxDisplayViewlet,
|
||||||
|
client: Client & TxOperations,
|
||||||
|
model: AttributeModel[]
|
||||||
|
): Promise<{ viewlet: TxDisplayViewlet, model: AttributeModel[] }> {
|
||||||
|
if (dtx.tx._class === core.class.TxCreateDoc) {
|
||||||
|
// Check if we have a class presenter we could have a pseudo viewlet based on class presenter.
|
||||||
|
viewlet = await createPseudoViewlet(client, dtx, 'created')
|
||||||
|
}
|
||||||
|
if (dtx.tx._class === core.class.TxRemoveDoc) {
|
||||||
|
viewlet = await createPseudoViewlet(client, dtx, 'deleted')
|
||||||
|
}
|
||||||
|
if (dtx.tx._class === core.class.TxUpdateDoc) {
|
||||||
|
model = await createUpdateModel(dtx, client, model)
|
||||||
|
}
|
||||||
|
return { viewlet, model }
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createUpdateModel (
|
||||||
|
dtx: DisplayTx,
|
||||||
|
client: Client & TxOperations,
|
||||||
|
model: AttributeModel[]
|
||||||
|
): Promise<AttributeModel[]> {
|
||||||
|
if (dtx.updateTx !== undefined) {
|
||||||
|
const _class = dtx.updateTx.objectClass
|
||||||
|
const ops = {
|
||||||
|
client,
|
||||||
|
_class,
|
||||||
|
keys: Object.keys(dtx.updateTx.operations).filter((id) => !id.startsWith('$')),
|
||||||
|
ignoreMissing: true
|
||||||
|
}
|
||||||
|
const hiddenAttrs = getHiddenAttrs(client, _class)
|
||||||
|
model = (await buildModel(ops)).filter((x) => !hiddenAttrs.has(x.key))
|
||||||
|
} else if (dtx.mixinTx !== undefined) {
|
||||||
|
const _class = dtx.mixinTx.mixin
|
||||||
|
const ops = {
|
||||||
|
client,
|
||||||
|
_class,
|
||||||
|
keys: Object.keys(dtx.mixinTx.attributes).filter((id) => !id.startsWith('$')),
|
||||||
|
ignoreMissing: true
|
||||||
|
}
|
||||||
|
const hiddenAttrs = getHiddenAttrs(client, _class)
|
||||||
|
model = (await buildModel(ops)).filter((x) => !hiddenAttrs.has(x.key))
|
||||||
|
}
|
||||||
|
return model
|
||||||
|
}
|
||||||
|
|
||||||
|
function getHiddenAttrs (client: Client & TxOperations, _class: Ref<Class<Doc>>): Set<string> {
|
||||||
|
return new Set(
|
||||||
|
[...client.getHierarchy().getAllAttributes(_class).entries()]
|
||||||
|
.filter(([, attr]) => attr.hidden === true)
|
||||||
|
.map(([k]) => k)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getValue (client: Client & TxOperations, m: AttributeModel, utx: any): Promise<any> {
|
||||||
|
const val = utx[m.key]
|
||||||
|
|
||||||
|
if (client.getHierarchy().isDerived(m._class, core.class.Doc) && typeof val === 'string') {
|
||||||
|
// We have an reference, we need to find a real object to pass for presenter
|
||||||
|
return await client.findOne(m._class, { _id: val as Ref<Doc> })
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
@ -19,4 +19,8 @@
|
|||||||
<path d="M13.3,8.3c-0.1,2.8-2.5,5.1-5.4,5.1C5,13.4,2.6,11,2.6,8c0-2.9,2.3-5.2,5.1-5.4c0.1-0.4,0.2-0.7,0.4-1c0,0-0.1,0-0.1,0 C4.4,1.7,1.6,4.5,1.6,8c0,3.5,2.9,6.4,6.4,6.4s6.4-2.9,6.4-6.4c0,0,0-0.1,0-0.1C14,8.1,13.7,8.2,13.3,8.3z"/>
|
<path d="M13.3,8.3c-0.1,2.8-2.5,5.1-5.4,5.1C5,13.4,2.6,11,2.6,8c0-2.9,2.3-5.2,5.1-5.4c0.1-0.4,0.2-0.7,0.4-1c0,0-0.1,0-0.1,0 C4.4,1.7,1.6,4.5,1.6,8c0,3.5,2.9,6.4,6.4,6.4s6.4-2.9,6.4-6.4c0,0,0-0.1,0-0.1C14,8.1,13.7,8.2,13.3,8.3z"/>
|
||||||
<ellipse cx="12.1" cy="3.9" rx="2.5" ry="2.5"/>
|
<ellipse cx="12.1" cy="3.9" rx="2.5" ry="2.5"/>
|
||||||
</symbol>
|
</symbol>
|
||||||
|
<symbol id="task-state" viewBox="0 0 16 16">
|
||||||
|
<path d="M13.3,8.3c-0.1,2.8-2.5,5.1-5.4,5.1C5,13.4,2.6,11,2.6,8c0-2.9,2.3-5.2,5.1-5.4c0.1-0.4,0.2-0.7,0.4-1c0,0-0.1,0-0.1,0 C4.4,1.7,1.6,4.5,1.6,8c0,3.5,2.9,6.4,6.4,6.4s6.4-2.9,6.4-6.4c0,0,0-0.1,0-0.1C14,8.1,13.7,8.2,13.3,8.3z"/>
|
||||||
|
<ellipse cx="12.1" cy="3.9" rx="2.5" ry="2.5"/>
|
||||||
|
</symbol>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2.2 KiB |
@ -22,7 +22,8 @@ loadMetadata(task.icon, {
|
|||||||
Kanban: `${icons}#kanban`,
|
Kanban: `${icons}#kanban`,
|
||||||
TodoCheck: `${icons}#todo-check`,
|
TodoCheck: `${icons}#todo-check`,
|
||||||
TodoUnCheck: `${icons}#todo-uncheck`,
|
TodoUnCheck: `${icons}#todo-uncheck`,
|
||||||
ManageStatuses: `${icons}#manage-statuses`
|
ManageStatuses: `${icons}#manage-statuses`,
|
||||||
|
TaskState: `${icons}#task-state`
|
||||||
})
|
})
|
||||||
|
|
||||||
addStringsLoader(taskId, async (lang: string) => await import(`../lang/${lang}.json`))
|
addStringsLoader(taskId, async (lang: string) => await import(`../lang/${lang}.json`))
|
||||||
|
@ -212,7 +212,8 @@ const task = plugin(taskId, {
|
|||||||
Kanban: '' as Asset,
|
Kanban: '' as Asset,
|
||||||
TodoCheck: '' as Asset,
|
TodoCheck: '' as Asset,
|
||||||
TodoUnCheck: '' as Asset,
|
TodoUnCheck: '' as Asset,
|
||||||
ManageStatuses: '' as Asset
|
ManageStatuses: '' as Asset,
|
||||||
|
TaskState: '' as Asset
|
||||||
},
|
},
|
||||||
global: {
|
global: {
|
||||||
// Global task root, if not attached to some other object.
|
// Global task root, if not attached to some other object.
|
||||||
|
@ -79,7 +79,8 @@ async function getAttributePresenter (client: Client, _class: Ref<Class<Obj>>, k
|
|||||||
sortingKey,
|
sortingKey,
|
||||||
_class: attrClass,
|
_class: attrClass,
|
||||||
label: preserveKey.label ?? attribute.label,
|
label: preserveKey.label ?? attribute.label,
|
||||||
presenter
|
presenter,
|
||||||
|
icon: presenterMixin.icon
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +142,6 @@ export async function buildModel (options: BuildModelOptions): Promise<Attribute
|
|||||||
return errorPresenter
|
return errorPresenter
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
console.log(model)
|
|
||||||
return (await Promise.all(model)).filter(a => a !== undefined) as AttributeModel[]
|
return (await Promise.all(model)).filter(a => a !== undefined) as AttributeModel[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,6 +108,8 @@ export interface AttributeModel {
|
|||||||
// Extra properties for component
|
// Extra properties for component
|
||||||
props?: Record<string, any>
|
props?: Record<string, any>
|
||||||
sortingKey: string
|
sortingKey: string
|
||||||
|
// Extra icon if applicable
|
||||||
|
icon?: Asset
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user