From a1e557a9b94b060fe1165add13eb65952101380d Mon Sep 17 00:00:00 2001 From: Anna No Date: Fri, 8 Apr 2022 10:08:30 +0700 Subject: [PATCH] Board: 1265: Make Card Actions extensible (#1319) Signed-off-by: Anna No --- models/board/src/index.ts | 181 +++++++++++++++++- models/board/src/migration.ts | 3 +- models/board/src/plugin.ts | 34 +++- .../src/components/editor/CardActions.svelte | 81 ++++++-- .../board-resources/src/models/CardAction.ts | 17 -- .../src/utils/CardActionUtils.ts | 87 +-------- plugins/board/src/index.ts | 28 ++- 7 files changed, 305 insertions(+), 126 deletions(-) delete mode 100644 plugins/board-resources/src/models/CardAction.ts diff --git a/models/board/src/index.ts b/models/board/src/index.ts index aa40032310..b92509ffe8 100644 --- a/models/board/src/index.ts +++ b/models/board/src/index.ts @@ -15,17 +15,18 @@ // // To help typescript locate view plugin properly -import type { Board, Card } from '@anticrm/board' +import type { Board, Card, CardAction } from '@anticrm/board' import type { Employee } from '@anticrm/contact' -import { Doc, FindOptions, IndexKind, Ref } from '@anticrm/core' +import { Client, Doc, DOMAIN_MODEL, FindOptions, IndexKind, Ref } from '@anticrm/core' import { Builder, Collection, Index, Model, Prop, TypeMarkup, TypeRef, TypeString, UX } from '@anticrm/model' import attachment from '@anticrm/model-attachment' import chunter from '@anticrm/model-chunter' import contact from '@anticrm/model-contact' -import core from '@anticrm/model-core' +import core, { TDoc } from '@anticrm/model-core' import task, { TSpaceWithStates, TTask } from '@anticrm/model-task' import view from '@anticrm/model-view' import workbench from '@anticrm/model-workbench' +import { Asset, IntlString, Resource } from '@anticrm/platform' import type {} from '@anticrm/view' import board from './plugin' @@ -64,8 +65,21 @@ export class TCard extends TTask implements Card { members!: Ref[] } +@Model(board.class.CardAction, core.class.Doc, DOMAIN_MODEL) +export class TCardAction extends TDoc implements CardAction { + hint?: IntlString + icon!: Asset + isInline?: boolean + isTransparent?: boolean + label!: IntlString + position!: number + type!: string + handler?: Resource<(card: Card, client: Client) => void> + supported?: Resource<(card: Card, client: Client) => boolean> +} + export function createModel (builder: Builder): void { - builder.createModel(TBoard, TCard) + builder.createModel(TBoard, TCard, TCardAction) builder.mixin(board.class.Board, core.class.Class, workbench.mixin.SpaceView, { view: { @@ -187,6 +201,165 @@ export function createModel (builder: Builder): void { }, board.viewlet.Kanban ) + + // card actions + builder.createDoc( + board.class.CardAction, + core.space.Model, + { + icon: board.icon.Card, + isInline: true, + label: board.string.Members, + position: 10, + type: board.cardActionType.AddToCard, + handler: board.cardActionHandler.Members + }, + board.cardAction.Members + ) + builder.createDoc( + board.class.CardAction, + core.space.Model, + { + icon: board.icon.Card, + isInline: true, + label: board.string.Labels, + position: 20, + type: board.cardActionType.AddToCard, + handler: board.cardActionHandler.Labels + }, + board.cardAction.Labels + ) + builder.createDoc( + board.class.CardAction, + core.space.Model, + { + icon: board.icon.Card, + isInline: false, + label: board.string.Checklist, + position: 30, + type: board.cardActionType.AddToCard, + handler: board.cardActionHandler.Checklist + }, + board.cardAction.Checklist + ) + builder.createDoc( + board.class.CardAction, + core.space.Model, + { + icon: board.icon.Card, + isInline: true, + label: board.string.Dates, + position: 40, + type: board.cardActionType.AddToCard, + handler: board.cardActionHandler.Dates + }, + board.cardAction.Dates + ) + builder.createDoc( + board.class.CardAction, + core.space.Model, + { + icon: board.icon.Card, + isInline: false, + label: board.string.Attachments, + position: 50, + type: board.cardActionType.AddToCard, + handler: board.cardActionHandler.Attachments + }, + board.cardAction.Attachments + ) + builder.createDoc( + board.class.CardAction, + core.space.Model, + { + icon: board.icon.Card, + isInline: false, + label: board.string.CustomFields, + position: 60, + type: board.cardActionType.AddToCard, + handler: board.cardActionHandler.CustomFields + }, + board.cardAction.CustomFields + ) + builder.createDoc( + board.class.CardAction, + core.space.Model, + { + icon: board.icon.Card, + isInline: false, + isTransparent: true, + label: board.string.AddButton, + position: 70, + type: board.cardActionType.Automation, + handler: board.cardActionHandler.AddButton + }, + board.cardAction.AddButton + ) + builder.createDoc( + board.class.CardAction, + core.space.Model, + { + icon: board.icon.Card, + isInline: true, + label: board.string.Move, + position: 80, + type: board.cardActionType.Action, + handler: board.cardActionHandler.Move + }, + board.cardAction.Move + ) + builder.createDoc( + board.class.CardAction, + core.space.Model, + { + icon: board.icon.Card, + isInline: true, + label: board.string.Copy, + position: 90, + type: board.cardActionType.Action, + handler: board.cardActionHandler.Copy + }, + board.cardAction.Copy + ) + builder.createDoc( + board.class.CardAction, + core.space.Model, + { + icon: board.icon.Card, + isInline: false, + label: board.string.MakeTemplate, + position: 100, + type: board.cardActionType.Action, + handler: board.cardActionHandler.MakeTemplate + }, + board.cardAction.MakeTemplate + ) + builder.createDoc( + board.class.CardAction, + core.space.Model, + { + icon: board.icon.Card, + isInline: false, + label: board.string.Watch, + position: 110, + type: board.cardActionType.Action, + handler: board.cardActionHandler.Watch + }, + board.cardAction.Watch + ) + builder.createDoc( + board.class.CardAction, + core.space.Model, + { + icon: board.icon.Card, + isInline: true, + label: board.string.Archive, + position: 120, + type: board.cardActionType.Action, + handler: board.cardActionHandler.Archive + }, + board.cardAction.Archive + ) } export { createDeps } from './creation' diff --git a/models/board/src/migration.ts b/models/board/src/migration.ts index 7ad0178911..cb7806bbb2 100644 --- a/models/board/src/migration.ts +++ b/models/board/src/migration.ts @@ -41,8 +41,7 @@ async function createSpace (tx: TxOperations): Promise { } export const boardOperation: MigrateOperation = { - async migrate (client: MigrationClient): Promise { - }, + async migrate (client: MigrationClient): Promise {}, async upgrade (client: MigrationUpgradeClient): Promise { const ops = new TxOperations(client, core.account.System) await createSpace(ops) diff --git a/models/board/src/plugin.ts b/models/board/src/plugin.ts index 09d4385169..8e99acbbf0 100644 --- a/models/board/src/plugin.ts +++ b/models/board/src/plugin.ts @@ -14,10 +14,10 @@ // limitations under the License. // -import { boardId } from '@anticrm/board' +import { boardId, Card, CardAction } from '@anticrm/board' import board from '@anticrm/board-resources/src/plugin' -import type { Ref, Space } from '@anticrm/core' -import { mergeIds } from '@anticrm/platform' +import type { Client, Ref, Space } from '@anticrm/core' +import { mergeIds, Resource } from '@anticrm/platform' import { KanbanTemplate, Sequence } from '@anticrm/task' import type { AnyComponent } from '@anticrm/ui' import { ViewletDescriptor } from '@anticrm/view' @@ -32,6 +32,34 @@ export default mergeIds(boardId, board, { Cards: '' as AnyComponent, KanbanView: '' as AnyComponent }, + cardAction: { + Members: '' as Ref, + Labels: '' as Ref, + Checklist: '' as Ref, + Dates: '' as Ref, + Attachments: '' as Ref, + CustomFields: '' as Ref, + AddButton: '' as Ref, + Move: '' as Ref, + Copy: '' as Ref, + MakeTemplate: '' as Ref, + Watch: '' as Ref, + Archive: '' as Ref + }, + cardActionHandler: { + Members: '' as Resource<(card: Card, client: Client) => void>, + Labels: '' as Resource<(card: Card, client: Client) => void>, + Checklist: '' as Resource<(card: Card, client: Client) => void>, + Dates: '' as Resource<(card: Card, client: Client) => void>, + Attachments: '' as Resource<(card: Card, client: Client) => void>, + CustomFields: '' as Resource<(card: Card, client: Client) => void>, + AddButton: '' as Resource<(card: Card, client: Client) => void>, + Move: '' as Resource<(card: Card, client: Client) => void>, + Copy: '' as Resource<(card: Card, client: Client) => void>, + MakeTemplate: '' as Resource<(card: Card, client: Client) => void>, + Watch: '' as Resource<(card: Card, client: Client) => void>, + Archive: '' as Resource<(card: Card, client: Client) => void> + }, space: { DefaultBoard: '' as Ref }, diff --git a/plugins/board-resources/src/components/editor/CardActions.svelte b/plugins/board-resources/src/components/editor/CardActions.svelte index b7b0b7eb0f..fd47b21cfc 100644 --- a/plugins/board-resources/src/components/editor/CardActions.svelte +++ b/plugins/board-resources/src/components/editor/CardActions.svelte @@ -14,30 +14,81 @@ // limitations under the License. --> {#if value}
{#each actionGroups as group} -
-
+ {#if group.actions.length > 0} +
+
+ {/if} {/each}
{/if} diff --git a/plugins/board-resources/src/models/CardAction.ts b/plugins/board-resources/src/models/CardAction.ts deleted file mode 100644 index 9e573b49bc..0000000000 --- a/plugins/board-resources/src/models/CardAction.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Card } from '@anticrm/board' -import { Asset, IntlString } from '@anticrm/platform' -import { AnySvelteComponent } from '@anticrm/ui' - -export interface CardActionGroup { - actions: CardAction[] - hint?: IntlString - label: IntlString -} - -export interface CardAction { - hint?: IntlString - icon: Asset | AnySvelteComponent - isTransparent?: boolean - label: IntlString - handler?: (card: Card) => void -} diff --git a/plugins/board-resources/src/utils/CardActionUtils.ts b/plugins/board-resources/src/utils/CardActionUtils.ts index 39d7fb8a01..d14358abc1 100644 --- a/plugins/board-resources/src/utils/CardActionUtils.ts +++ b/plugins/board-resources/src/utils/CardActionUtils.ts @@ -1,86 +1,9 @@ -import { Card } from '@anticrm/board' -import { IconAdd, IconAttachment } from '@anticrm/ui' -import { CardAction, CardActionGroup } from '../models/CardAction' +import { CardAction } from '@anticrm/board' +import { Client } from '@anticrm/core' import board from '../plugin' -export const MembersAction: CardAction = { - icon: board.icon.Card, - label: board.string.Members -} +export const cardActionSorter = (a1: CardAction, a2: CardAction) => a1.position - a2.position -export const LabelsAction: CardAction = { - icon: board.icon.Card, - label: board.string.Labels -} - -export const ChecklistAction: CardAction = { - icon: board.icon.Card, - label: board.string.Checklist -} - -export const DatesAction: CardAction = { - icon: board.icon.Card, - label: board.string.Dates -} - -export const AttachmentsAction: CardAction = { - icon: IconAttachment, - label: board.string.Attachments -} - -export const CustomFieldsAction: CardAction = { - icon: board.icon.Card, - label: board.string.CustomFields -} - -export const AddButtonAction: CardAction = { - icon: IconAdd, - isTransparent: true, - label: board.string.AddButton -} - -export const MoveAction: CardAction = { - icon: board.icon.Card, - label: board.string.Move -} - -export const CopyAction: CardAction = { - icon: board.icon.Card, - label: board.string.Copy -} - -export const MakeTemplateAction: CardAction = { - icon: board.icon.Card, - label: board.string.MakeTemplate -} - -export const WatchAction: CardAction = { - icon: board.icon.Card, - label: board.string.Watch -} - -export const ArchiveAction: CardAction = { - icon: board.icon.Card, - label: board.string.Archive -} - -export const getEditorCardActionGroups = (card: Card): CardActionGroup[] => { - if (card === undefined) { - return [] - } - - return [ - { - label: board.string.AddToCard, - actions: [MembersAction, LabelsAction, ChecklistAction, DatesAction, AttachmentsAction, CustomFieldsAction] - }, - { - label: board.string.Automation, - actions: [AddButtonAction] - }, - { - label: board.string.Actions, - actions: [MoveAction, CopyAction, MakeTemplateAction, WatchAction, ArchiveAction] - } - ] +export const getCardActions = (client: Client) => { + return client.findAll(board.class.CardAction, {}) } diff --git a/plugins/board/src/index.ts b/plugins/board/src/index.ts index d9f5408f0e..4918362861 100644 --- a/plugins/board/src/index.ts +++ b/plugins/board/src/index.ts @@ -15,8 +15,8 @@ // import { Employee } from '@anticrm/contact' -import type { AttachedDoc, Class, Doc, Markup, Ref } from '@anticrm/core' -import type { Asset, Plugin } from '@anticrm/platform' +import type { AttachedDoc, Class, Client, Doc, Markup, Ref } from '@anticrm/core' +import type { Asset, IntlString, Plugin, Resource } from '@anticrm/platform' import { plugin } from '@anticrm/platform' import type { KanbanTemplateSpace, SpaceWithStates, Task } from '@anticrm/task' @@ -65,6 +65,20 @@ export interface Card extends Task { comments?: number attachments?: number } +/** + * @public + */ +export interface CardAction extends Doc { + hint?: IntlString + icon: Asset + isInline?: boolean + isTransparent?: boolean + label: IntlString + position: number + type: string + handler?: Resource<(card: Card, client: Client) => void> + supported?: Resource<(card: Card, client: Client) => boolean> +} /** * @public @@ -78,9 +92,17 @@ const boards = plugin(boardId, { app: { Board: '' as Ref }, + cardActionType: { + Editor: 'Editor', + Cover: 'Cover', + AddToCard: 'AddToCard', + Automation: 'Automation', + Action: 'Action' + }, class: { Board: '' as Ref>, - Card: '' as Ref> + Card: '' as Ref>, + CardAction: '' as Ref> }, icon: { Board: '' as Asset,