mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-22 08:20:39 +00:00
Board: Use Standard actions (#1766)
* Board: use standard actions Signed-off-by: Anna No <anna.no@xored.com> * Board: use standard actions Signed-off-by: Anna No <anna.no@xored.com> * fix lint issues Signed-off-by: Anna No <anna.no@xored.com> * fix lint issues Signed-off-by: Anna No <anna.no@xored.com> * fix merge conflicts Signed-off-by: Anna No <anna.no@xored.com> * fix merge conflicts Signed-off-by: Anna No <anna.no@xored.com>
This commit is contained in:
parent
7b49752288
commit
29058d8c84
@ -14,9 +14,9 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
// To help typescript locate view plugin properly
|
// To help typescript locate view plugin properly
|
||||||
import type { Board, Card, CardAction, CardDate, CardLabel, MenuPage, LabelsCompactMode } from '@anticrm/board'
|
import type { Board, Card, CardDate, CardLabel, MenuPage, LabelsCompactMode } from '@anticrm/board'
|
||||||
import type { Employee } from '@anticrm/contact'
|
import type { Employee } from '@anticrm/contact'
|
||||||
import { DOMAIN_MODEL, IndexKind, Markup, Ref, Timestamp, TxOperations as Client, Type } from '@anticrm/core'
|
import { DOMAIN_MODEL, IndexKind, Markup, Ref, Timestamp, Type } from '@anticrm/core'
|
||||||
import {
|
import {
|
||||||
ArrOf,
|
ArrOf,
|
||||||
Builder,
|
Builder,
|
||||||
@ -35,9 +35,9 @@ import chunter from '@anticrm/model-chunter'
|
|||||||
import contact from '@anticrm/model-contact'
|
import contact from '@anticrm/model-contact'
|
||||||
import core, { TAttachedDoc, TDoc, TObj } from '@anticrm/model-core'
|
import core, { TAttachedDoc, TDoc, TObj } from '@anticrm/model-core'
|
||||||
import task, { TSpaceWithStates, TTask } from '@anticrm/model-task'
|
import task, { TSpaceWithStates, TTask } from '@anticrm/model-task'
|
||||||
import view from '@anticrm/model-view'
|
import view, { actionTemplates, createAction } from '@anticrm/model-view'
|
||||||
import workbench from '@anticrm/model-workbench'
|
import workbench from '@anticrm/model-workbench'
|
||||||
import { Asset, IntlString, Resource } from '@anticrm/platform'
|
import { IntlString } from '@anticrm/platform'
|
||||||
import type { AnyComponent } from '@anticrm/ui'
|
import type { AnyComponent } from '@anticrm/ui'
|
||||||
import preference, { TPreference } from '@anticrm/model-preference'
|
import preference, { TPreference } from '@anticrm/model-preference'
|
||||||
import board from './plugin'
|
import board from './plugin'
|
||||||
@ -115,20 +115,6 @@ export class TCard extends TTask implements Card {
|
|||||||
members?: Ref<Employee>[]
|
members?: Ref<Employee>[]
|
||||||
}
|
}
|
||||||
|
|
||||||
@Model(board.class.CardAction, core.class.Doc, DOMAIN_MODEL)
|
|
||||||
export class TCardAction extends TDoc implements CardAction {
|
|
||||||
component?: AnyComponent
|
|
||||||
hint?: IntlString
|
|
||||||
icon!: Asset
|
|
||||||
isInline?: boolean
|
|
||||||
kind?: 'primary' | 'secondary' | 'no-border' | 'transparent' | 'dangerous'
|
|
||||||
label!: IntlString
|
|
||||||
position!: number
|
|
||||||
type!: string
|
|
||||||
handler?: Resource<(card: Card, client: Client, e?: Event) => void>
|
|
||||||
supported?: Resource<(card: Card, client: Client) => boolean>
|
|
||||||
}
|
|
||||||
|
|
||||||
@Model(board.class.MenuPage, core.class.Doc, DOMAIN_MODEL)
|
@Model(board.class.MenuPage, core.class.Doc, DOMAIN_MODEL)
|
||||||
export class TMenuPage extends TDoc implements MenuPage {
|
export class TMenuPage extends TDoc implements MenuPage {
|
||||||
component!: AnyComponent
|
component!: AnyComponent
|
||||||
@ -137,7 +123,7 @@ export class TMenuPage extends TDoc implements MenuPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function createModel (builder: Builder): void {
|
export function createModel (builder: Builder): void {
|
||||||
builder.createModel(TBoard, TCard, TCardLabel, TCardDate, TCardAction, TMenuPage, TLabelsCompactMode)
|
builder.createModel(TBoard, TCard, TCardLabel, TCardDate, TMenuPage, TLabelsCompactMode)
|
||||||
|
|
||||||
builder.createDoc(board.class.MenuPage, core.space.Model, {
|
builder.createDoc(board.class.MenuPage, core.space.Model, {
|
||||||
component: board.component.Archive,
|
component: board.component.Archive,
|
||||||
@ -278,207 +264,156 @@ export function createModel (builder: Builder): void {
|
|||||||
)
|
)
|
||||||
|
|
||||||
// card actions
|
// card actions
|
||||||
builder.createDoc(
|
createAction(
|
||||||
board.class.CardAction,
|
builder,
|
||||||
core.space.Model,
|
|
||||||
{
|
{
|
||||||
icon: board.icon.Card,
|
action: view.actionImpl.ShowPopup,
|
||||||
isInline: false,
|
actionProps: {
|
||||||
label: board.string.Join,
|
component: board.component.LabelsActionPopup,
|
||||||
position: 10,
|
element: 'top'
|
||||||
type: board.cardActionType.Suggested,
|
},
|
||||||
handler: board.cardActionHandler.Join,
|
|
||||||
supported: board.cardActionSupportedHandler.Join
|
|
||||||
},
|
|
||||||
board.cardAction.Join
|
|
||||||
)
|
|
||||||
builder.createDoc(
|
|
||||||
board.class.CardAction,
|
|
||||||
core.space.Model,
|
|
||||||
{
|
|
||||||
icon: board.icon.Card,
|
|
||||||
isInline: true,
|
|
||||||
label: board.string.Members,
|
|
||||||
position: 20,
|
|
||||||
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,
|
label: board.string.Labels,
|
||||||
position: 30,
|
|
||||||
type: board.cardActionType.AddToCard,
|
|
||||||
handler: board.cardActionHandler.Labels
|
|
||||||
},
|
|
||||||
board.cardAction.Labels
|
|
||||||
)
|
|
||||||
builder.createDoc(
|
|
||||||
board.class.CardAction,
|
|
||||||
core.space.Model,
|
|
||||||
{
|
|
||||||
icon: board.icon.Card,
|
icon: board.icon.Card,
|
||||||
isInline: false,
|
input: 'any',
|
||||||
label: board.string.Checklist,
|
category: board.category.Card,
|
||||||
position: 40,
|
target: board.class.Card,
|
||||||
type: board.cardActionType.AddToCard,
|
context: { mode: 'context', application: board.app.Board, group: 'top' }
|
||||||
handler: board.cardActionHandler.Checklist
|
|
||||||
},
|
},
|
||||||
board.cardAction.Checklist
|
board.action.Labels
|
||||||
)
|
)
|
||||||
builder.createDoc(
|
createAction(
|
||||||
board.class.CardAction,
|
builder,
|
||||||
core.space.Model,
|
|
||||||
{
|
{
|
||||||
icon: board.icon.Card,
|
action: view.actionImpl.ShowPopup,
|
||||||
isInline: true,
|
actionProps: {
|
||||||
|
component: board.component.DatesActionPopup,
|
||||||
|
element: 'top'
|
||||||
|
},
|
||||||
label: board.string.Dates,
|
label: board.string.Dates,
|
||||||
position: 50,
|
|
||||||
type: board.cardActionType.AddToCard,
|
|
||||||
handler: board.cardActionHandler.Dates
|
|
||||||
},
|
|
||||||
board.cardAction.Dates
|
|
||||||
)
|
|
||||||
builder.createDoc(
|
|
||||||
board.class.CardAction,
|
|
||||||
core.space.Model,
|
|
||||||
{
|
|
||||||
icon: board.icon.Card,
|
icon: board.icon.Card,
|
||||||
isInline: false,
|
input: 'any',
|
||||||
label: board.string.Attachments,
|
category: board.category.Card,
|
||||||
position: 60,
|
target: board.class.Card,
|
||||||
type: board.cardActionType.AddToCard,
|
context: { mode: 'context', application: board.app.Board, group: 'top' }
|
||||||
handler: board.cardActionHandler.Attachments
|
|
||||||
},
|
},
|
||||||
board.cardAction.Attachments
|
board.action.Dates
|
||||||
)
|
)
|
||||||
builder.createDoc(
|
createAction(
|
||||||
board.class.CardAction,
|
builder,
|
||||||
core.space.Model,
|
|
||||||
{
|
{
|
||||||
icon: board.icon.Card,
|
action: view.actionImpl.ShowPopup,
|
||||||
isInline: true,
|
actionProps: {
|
||||||
|
component: board.component.CoverActionPopup,
|
||||||
|
element: 'top'
|
||||||
|
},
|
||||||
label: board.string.Cover,
|
label: board.string.Cover,
|
||||||
position: 70,
|
|
||||||
type: board.cardActionType.Cover,
|
|
||||||
handler: board.cardActionHandler.Cover
|
|
||||||
},
|
|
||||||
board.cardAction.Cover
|
|
||||||
)
|
|
||||||
builder.createDoc(
|
|
||||||
board.class.CardAction,
|
|
||||||
core.space.Model,
|
|
||||||
{
|
|
||||||
icon: board.icon.Card,
|
icon: board.icon.Card,
|
||||||
isInline: false,
|
input: 'any',
|
||||||
label: board.string.CustomFields,
|
category: board.category.Card,
|
||||||
position: 80,
|
target: board.class.Card,
|
||||||
type: board.cardActionType.AddToCard,
|
context: { mode: 'context', application: board.app.Board, group: 'top' }
|
||||||
handler: board.cardActionHandler.CustomFields
|
|
||||||
},
|
},
|
||||||
board.cardAction.CustomFields
|
board.action.Cover
|
||||||
)
|
)
|
||||||
builder.createDoc(
|
createAction(
|
||||||
board.class.CardAction,
|
builder,
|
||||||
core.space.Model,
|
|
||||||
{
|
{
|
||||||
icon: board.icon.Card,
|
...actionTemplates.move,
|
||||||
isInline: false,
|
action: view.actionImpl.ShowPopup,
|
||||||
kind: 'transparent',
|
actionProps: {
|
||||||
label: board.string.AddButton,
|
component: board.component.MoveActionPopup,
|
||||||
position: 90,
|
element: 'top'
|
||||||
type: board.cardActionType.Automation,
|
},
|
||||||
handler: board.cardActionHandler.AddButton
|
input: 'any',
|
||||||
|
category: board.category.Card,
|
||||||
|
target: board.class.Card,
|
||||||
|
context: { mode: 'context', application: board.app.Board, group: 'tools' }
|
||||||
},
|
},
|
||||||
board.cardAction.AddButton
|
board.action.Move
|
||||||
)
|
)
|
||||||
builder.createDoc(
|
createAction(
|
||||||
board.class.CardAction,
|
builder,
|
||||||
core.space.Model,
|
|
||||||
{
|
{
|
||||||
icon: board.icon.Card,
|
action: view.actionImpl.ShowPopup,
|
||||||
isInline: true,
|
actionProps: {
|
||||||
label: board.string.Move,
|
component: board.component.CopyActionPopup,
|
||||||
position: 100,
|
element: 'top'
|
||||||
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,
|
label: board.string.Copy,
|
||||||
position: 110,
|
|
||||||
type: board.cardActionType.Action,
|
|
||||||
handler: board.cardActionHandler.Copy
|
|
||||||
},
|
|
||||||
board.cardAction.Copy
|
|
||||||
)
|
|
||||||
builder.createDoc(
|
|
||||||
board.class.CardAction,
|
|
||||||
core.space.Model,
|
|
||||||
{
|
|
||||||
icon: board.icon.Card,
|
icon: board.icon.Card,
|
||||||
isInline: false,
|
input: 'any',
|
||||||
label: board.string.MakeTemplate,
|
category: board.category.Card,
|
||||||
position: 120,
|
target: board.class.Card,
|
||||||
type: board.cardActionType.Action,
|
context: { mode: 'context', application: board.app.Board, group: 'tools' }
|
||||||
handler: board.cardActionHandler.MakeTemplate
|
|
||||||
},
|
},
|
||||||
board.cardAction.MakeTemplate
|
board.action.Copy
|
||||||
)
|
)
|
||||||
builder.createDoc(
|
|
||||||
board.class.CardAction,
|
createAction(
|
||||||
core.space.Model,
|
builder,
|
||||||
{
|
{
|
||||||
|
action: view.actionImpl.UpdateDocument,
|
||||||
|
actionProps: {
|
||||||
|
key: 'isArchived',
|
||||||
|
value: true,
|
||||||
|
ask: true,
|
||||||
|
label: task.string.Archive,
|
||||||
|
message: task.string.ArchiveConfirm
|
||||||
|
},
|
||||||
|
query: {
|
||||||
|
isArchived: { $nin: [true] }
|
||||||
|
},
|
||||||
|
label: board.string.Archive,
|
||||||
icon: board.icon.Card,
|
icon: board.icon.Card,
|
||||||
isInline: true,
|
input: 'any',
|
||||||
label: board.string.ToArchive,
|
category: board.category.Card,
|
||||||
position: 140,
|
target: board.class.Card,
|
||||||
type: board.cardActionType.Action,
|
context: { mode: 'context', application: board.app.Board, group: 'tools' }
|
||||||
handler: board.cardActionHandler.Archive,
|
|
||||||
supported: board.cardActionSupportedHandler.Archive
|
|
||||||
},
|
},
|
||||||
board.cardAction.Archive
|
board.action.Archive
|
||||||
)
|
)
|
||||||
builder.createDoc(
|
createAction(
|
||||||
board.class.CardAction,
|
builder,
|
||||||
core.space.Model,
|
|
||||||
{
|
{
|
||||||
icon: board.icon.Card,
|
action: view.actionImpl.UpdateDocument,
|
||||||
isInline: true,
|
actionProps: {
|
||||||
|
key: 'isArchived',
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
query: {
|
||||||
|
isArchived: true
|
||||||
|
},
|
||||||
label: board.string.SendToBoard,
|
label: board.string.SendToBoard,
|
||||||
position: 140,
|
|
||||||
type: board.cardActionType.Action,
|
|
||||||
handler: board.cardActionHandler.SendToBoard,
|
|
||||||
supported: board.cardActionSupportedHandler.SendToBoard
|
|
||||||
},
|
|
||||||
board.cardAction.SendToBoard
|
|
||||||
)
|
|
||||||
builder.createDoc(
|
|
||||||
board.class.CardAction,
|
|
||||||
core.space.Model,
|
|
||||||
{
|
|
||||||
icon: board.icon.Card,
|
icon: board.icon.Card,
|
||||||
isInline: false,
|
input: 'any',
|
||||||
kind: 'dangerous',
|
category: board.category.Card,
|
||||||
label: board.string.Delete,
|
target: board.class.Card,
|
||||||
position: 150,
|
context: { mode: 'context', application: board.app.Board, group: 'tools' }
|
||||||
type: board.cardActionType.Action,
|
|
||||||
handler: board.cardActionHandler.Delete,
|
|
||||||
supported: board.cardActionSupportedHandler.Delete
|
|
||||||
},
|
},
|
||||||
board.cardAction.Delete
|
board.action.SendToBoard
|
||||||
)
|
)
|
||||||
|
|
||||||
|
createAction(
|
||||||
|
builder,
|
||||||
|
{
|
||||||
|
action: view.actionImpl.Delete,
|
||||||
|
query: {
|
||||||
|
isArchived: true
|
||||||
|
},
|
||||||
|
label: view.string.Delete,
|
||||||
|
icon: view.icon.Delete,
|
||||||
|
keyBinding: ['Meta + Backspace', 'Ctrl + Backspace'],
|
||||||
|
category: board.category.Card,
|
||||||
|
input: 'any',
|
||||||
|
target: board.class.Card,
|
||||||
|
context: { mode: 'context', application: board.app.Board, group: 'tools' }
|
||||||
|
},
|
||||||
|
board.action.Delete
|
||||||
|
)
|
||||||
|
|
||||||
|
builder.mixin(board.class.Card, core.class.Class, view.mixin.IgnoreActions, {
|
||||||
|
actions: [view.action.Delete, task.action.Move]
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export { boardOperation } from './migration'
|
export { boardOperation } from './migration'
|
||||||
|
@ -34,7 +34,12 @@ export default mergeIds(boardId, board, {
|
|||||||
TemplatesIcon: '' as AnyComponent,
|
TemplatesIcon: '' as AnyComponent,
|
||||||
Cards: '' as AnyComponent,
|
Cards: '' as AnyComponent,
|
||||||
KanbanView: '' as AnyComponent,
|
KanbanView: '' as AnyComponent,
|
||||||
TableView: '' as AnyComponent
|
TableView: '' as AnyComponent,
|
||||||
|
LabelsActionPopup: '' as AnyComponent,
|
||||||
|
DatesActionPopup: '' as AnyComponent,
|
||||||
|
CoverActionPopup: '' as AnyComponent,
|
||||||
|
MoveActionPopup: '' as AnyComponent,
|
||||||
|
CopyActionPopup: '' as AnyComponent
|
||||||
},
|
},
|
||||||
space: {
|
space: {
|
||||||
DefaultBoard: '' as Ref<Space>
|
DefaultBoard: '' as Ref<Space>
|
||||||
|
@ -509,11 +509,15 @@ export function createModel (builder: Builder): void {
|
|||||||
task.completion.IssueCategory
|
task.completion.IssueCategory
|
||||||
)
|
)
|
||||||
|
|
||||||
createAction(builder, {
|
createAction(
|
||||||
...viewTemplates.move,
|
builder,
|
||||||
target: task.class.Task,
|
{
|
||||||
context: {
|
...viewTemplates.move,
|
||||||
mode: ['context', 'browser']
|
target: task.class.Task,
|
||||||
}
|
context: {
|
||||||
})
|
mode: ['context', 'browser']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
task.action.Move
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,8 @@ export default mergeIds(taskId, task, {
|
|||||||
action: {
|
action: {
|
||||||
EditStatuses: '' as Ref<Action>,
|
EditStatuses: '' as Ref<Action>,
|
||||||
ArchiveSpace: '' as Ref<Action>,
|
ArchiveSpace: '' as Ref<Action>,
|
||||||
UnarchiveSpace: '' as Ref<Action>
|
UnarchiveSpace: '' as Ref<Action>,
|
||||||
|
Move: '' as Ref<Action>
|
||||||
},
|
},
|
||||||
actionImpl: {
|
actionImpl: {
|
||||||
EditStatuses: '' as ViewAction,
|
EditStatuses: '' as ViewAction,
|
||||||
|
@ -1,15 +1,18 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Button, Label } from '@anticrm/ui'
|
|
||||||
import { createQuery, getClient } from '@anticrm/presentation'
|
|
||||||
import { Card } from '@anticrm/board'
|
import { Card } from '@anticrm/board'
|
||||||
import { DocumentQuery, SortingOrder } from '@anticrm/core'
|
import { DocumentQuery, SortingOrder } from '@anticrm/core'
|
||||||
import { getResource } from '@anticrm/platform'
|
import { createQuery, getClient } from '@anticrm/presentation'
|
||||||
|
import { Button, Label } from '@anticrm/ui'
|
||||||
|
import type { Action } from '@anticrm/view'
|
||||||
|
import { invokeAction } from '@anticrm/view-resources'
|
||||||
import board from '../plugin'
|
import board from '../plugin'
|
||||||
|
import { getCardActions } from '../utils/CardActionUtils'
|
||||||
import KanbanCard from './KanbanCard.svelte'
|
import KanbanCard from './KanbanCard.svelte'
|
||||||
|
|
||||||
export let query: DocumentQuery<Card> = {}
|
export let query: DocumentQuery<Card> = {}
|
||||||
|
|
||||||
let archivedCards: Card[]
|
let archivedCards: Card[]
|
||||||
|
let actions: Action[] = []
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
const cardQuery = createQuery()
|
const cardQuery = createQuery()
|
||||||
$: cardQuery.query(
|
$: cardQuery.query(
|
||||||
@ -20,6 +23,9 @@
|
|||||||
},
|
},
|
||||||
{ sort: { rank: SortingOrder.Descending } }
|
{ sort: { rank: SortingOrder.Descending } }
|
||||||
)
|
)
|
||||||
|
getCardActions(client, { _id: { $in: [board.action.SendToBoard, board.action.Delete] } }).then(async (result) => {
|
||||||
|
actions = result
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if archivedCards}
|
{#if archivedCards}
|
||||||
@ -33,16 +39,20 @@
|
|||||||
<div class="flex-center flex-gap-2 w-full">
|
<div class="flex-center flex-gap-2 w-full">
|
||||||
<Button
|
<Button
|
||||||
label={board.string.SendToBoard}
|
label={board.string.SendToBoard}
|
||||||
on:click={async (e) => {
|
on:click={(e) => {
|
||||||
const unarchiveAction = await getResource(board.cardActionHandler.SendToBoard)
|
const unarchiveAction = actions.find((a) => a._id === board.action.SendToBoard)
|
||||||
unarchiveAction(card, client, e)
|
if (unarchiveAction) {
|
||||||
|
invokeAction(card, e, unarchiveAction.action, unarchiveAction.actionProps)
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
label={board.string.Delete}
|
label={board.string.Delete}
|
||||||
on:click={async (e) => {
|
on:click={async (e) => {
|
||||||
const deleteAction = await getResource(board.cardActionHandler.Delete)
|
const deleteAction = actions.find((a) => a._id === board.action.Delete)
|
||||||
deleteAction(card, client, e)
|
if (deleteAction) {
|
||||||
|
invokeAction(card, e, deleteAction.action, deleteAction.actionProps)
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -17,13 +17,12 @@
|
|||||||
import type { Card } from '@anticrm/board'
|
import type { Card } from '@anticrm/board'
|
||||||
import { Class, Ref } from '@anticrm/core'
|
import { Class, Ref } from '@anticrm/core'
|
||||||
import { Panel } from '@anticrm/panel'
|
import { Panel } from '@anticrm/panel'
|
||||||
import { getResource } from '@anticrm/platform'
|
|
||||||
import { createQuery, getClient } from '@anticrm/presentation'
|
import { createQuery, getClient } from '@anticrm/presentation'
|
||||||
import type { State, TodoItem } from '@anticrm/task'
|
import type { State, TodoItem } from '@anticrm/task'
|
||||||
import task from '@anticrm/task'
|
import task from '@anticrm/task'
|
||||||
import { StyledTextBox } from '@anticrm/text-editor'
|
import { StyledTextBox } from '@anticrm/text-editor'
|
||||||
import { Button, EditBox, Icon, Label } from '@anticrm/ui'
|
import { Button, EditBox, Icon, Label } from '@anticrm/ui'
|
||||||
import { UpDownNavigator } from '@anticrm/view-resources'
|
import { invokeAction, UpDownNavigator } from '@anticrm/view-resources'
|
||||||
import { createEventDispatcher, onMount } from 'svelte'
|
import { createEventDispatcher, onMount } from 'svelte'
|
||||||
import board from '../plugin'
|
import board from '../plugin'
|
||||||
import { getCardActions } from '../utils/CardActionUtils'
|
import { getCardActions } from '../utils/CardActionUtils'
|
||||||
@ -66,13 +65,13 @@
|
|||||||
checklists = result
|
checklists = result
|
||||||
})
|
})
|
||||||
|
|
||||||
getCardActions(client, { _id: board.cardAction.Move }).then(async (result) => {
|
getCardActions(client, { _id: board.action.Move }).then(async (result) => {
|
||||||
if (result[0]?.handler) {
|
if (result[0]) {
|
||||||
const handler = await getResource(result[0].handler)
|
|
||||||
handleMove = (e) => {
|
handleMove = (e) => {
|
||||||
if (object) {
|
if (!object) {
|
||||||
handler(object, client, e)
|
return
|
||||||
}
|
}
|
||||||
|
invokeAction(object, e, result[0].action, result[0].actionProps)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -22,8 +22,8 @@
|
|||||||
import notification from '@anticrm/notification'
|
import notification from '@anticrm/notification'
|
||||||
import { getClient, UserBoxList } from '@anticrm/presentation'
|
import { getClient, UserBoxList } from '@anticrm/presentation'
|
||||||
import { Button, Component, EditBox, IconEdit, Label, numberToHexColor, showPopup } from '@anticrm/ui'
|
import { Button, Component, EditBox, IconEdit, Label, numberToHexColor, showPopup } from '@anticrm/ui'
|
||||||
|
import { ContextMenu } from '@anticrm/view-resources'
|
||||||
import board from '../plugin'
|
import board from '../plugin'
|
||||||
import CardInlineActions from './editor/CardInlineActions.svelte'
|
|
||||||
import CardLabels from './editor/CardLabels.svelte'
|
import CardLabels from './editor/CardLabels.svelte'
|
||||||
import DatePresenter from './presenters/DatePresenter.svelte'
|
import DatePresenter from './presenters/DatePresenter.svelte'
|
||||||
import { hasDate, openCardPanel, updateCard, updateCardMembers } from '../utils/CardUtils'
|
import { hasDate, openCardPanel, updateCard, updateCardMembers } from '../utils/CardUtils'
|
||||||
@ -44,12 +44,7 @@
|
|||||||
|
|
||||||
function enterEditMode (): void {
|
function enterEditMode (): void {
|
||||||
isEditMode = true
|
isEditMode = true
|
||||||
showPopup(
|
showPopup(ContextMenu, { object }, getElementPopupAlignment(ref, { h: 'right', v: 'top' }), exitEditMode)
|
||||||
CardInlineActions,
|
|
||||||
{ value: object },
|
|
||||||
getElementPopupAlignment(ref, { h: 'right', v: 'top' }),
|
|
||||||
exitEditMode
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function showCard () {
|
function showCard () {
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
import { showPopup } from '@anticrm/ui'
|
import { showPopup } from '@anticrm/ui'
|
||||||
import {
|
import {
|
||||||
ActionContext,
|
ActionContext,
|
||||||
|
ContextMenu,
|
||||||
focusStore,
|
focusStore,
|
||||||
ListSelectionProvider,
|
ListSelectionProvider,
|
||||||
SelectDirection,
|
SelectDirection,
|
||||||
@ -30,7 +31,6 @@
|
|||||||
} from '@anticrm/view-resources'
|
} from '@anticrm/view-resources'
|
||||||
import { onMount } from 'svelte'
|
import { onMount } from 'svelte'
|
||||||
import AddCard from './add-card/AddCard.svelte'
|
import AddCard from './add-card/AddCard.svelte'
|
||||||
import CardInlineActions from './editor/CardInlineActions.svelte'
|
|
||||||
import KanbanCard from './KanbanCard.svelte'
|
import KanbanCard from './KanbanCard.svelte'
|
||||||
import AddPanel from './AddPanel.svelte'
|
import AddPanel from './AddPanel.svelte'
|
||||||
import ListHeader from './ListHeader.svelte'
|
import ListHeader from './ListHeader.svelte'
|
||||||
@ -94,8 +94,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
showPopup(
|
showPopup(
|
||||||
CardInlineActions,
|
ContextMenu,
|
||||||
{ value: object },
|
{ object },
|
||||||
{
|
{
|
||||||
getBoundingClientRect: () => DOMRect.fromRect({ width: 1, height: 1, x: ev.clientX, y: ev.clientY })
|
getBoundingClientRect: () => DOMRect.fromRect({ width: 1, height: 1, x: ev.clientX, y: ev.clientY })
|
||||||
}
|
}
|
||||||
|
@ -14,67 +14,26 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import board from '@anticrm/board'
|
import type { Card } from '@anticrm/board'
|
||||||
import type { Card, CardAction } from '@anticrm/board'
|
|
||||||
import { IntlString, getResource } from '@anticrm/platform'
|
|
||||||
import { getClient } from '@anticrm/presentation'
|
import { getClient } from '@anticrm/presentation'
|
||||||
import { Button, Component, Label } from '@anticrm/ui'
|
import { Button, IconAttachment, Label, showPopup } from '@anticrm/ui'
|
||||||
|
import type { Action } from '@anticrm/view'
|
||||||
|
import { getActions, invokeAction } from '@anticrm/view-resources'
|
||||||
|
import AddChecklist from '../popups/AddChecklist.svelte'
|
||||||
|
import AttachmentPicker from '../popups/AttachmentPicker.svelte'
|
||||||
import plugin from '../../plugin'
|
import plugin from '../../plugin'
|
||||||
import { cardActionSorter, getCardActions } from '../../utils/CardActionUtils'
|
import { getPopupAlignment } from '../../utils/PopupUtils'
|
||||||
|
|
||||||
export let value: Card
|
export let value: Card
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
|
|
||||||
let actionGroups: { label: IntlString; actions: CardAction[] }[] = []
|
let topActions: Action[] = []
|
||||||
|
let toolsActions: Action[] = []
|
||||||
async function fetch () {
|
async function fetch () {
|
||||||
const suggestedActions: CardAction[] = []
|
const result = await getActions(client, value, value._class)
|
||||||
const addToCardActions: CardAction[] = []
|
topActions = result.filter((action) => action.context.group === 'top')
|
||||||
const automationActions: CardAction[] = []
|
toolsActions = result.filter((action) => action.context.group !== 'top')
|
||||||
const actions: CardAction[] = []
|
|
||||||
const result = await getCardActions(client)
|
|
||||||
for (const action of result) {
|
|
||||||
let supported = true
|
|
||||||
if (action.supported) {
|
|
||||||
const supportedHandler = await getResource(action.supported)
|
|
||||||
supported = supportedHandler(value, client)
|
|
||||||
}
|
|
||||||
if (supported) {
|
|
||||||
if (action.type === board.cardActionType.Suggested) {
|
|
||||||
suggestedActions.push(action)
|
|
||||||
} else if (action.type === board.cardActionType.Cover) {
|
|
||||||
addToCardActions.push(action)
|
|
||||||
} else if (action.type === board.cardActionType.AddToCard) {
|
|
||||||
addToCardActions.push(action)
|
|
||||||
} else if (action.type === board.cardActionType.Automation) {
|
|
||||||
automationActions.push(action)
|
|
||||||
} else if (action.type === board.cardActionType.Action) {
|
|
||||||
actions.push(action)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
actionGroups = [
|
|
||||||
{
|
|
||||||
label: plugin.string.Suggested,
|
|
||||||
actions: suggestedActions.sort(cardActionSorter)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: plugin.string.AddToCard,
|
|
||||||
actions: addToCardActions.sort(cardActionSorter)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: plugin.string.Automation,
|
|
||||||
actions: automationActions.sort(cardActionSorter)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: plugin.string.Actions,
|
|
||||||
actions: actions.sort(cardActionSorter)
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fetch()
|
fetch()
|
||||||
$: value.members && fetch()
|
$: value.members && fetch()
|
||||||
$: value.isArchived && fetch()
|
$: value.isArchived && fetch()
|
||||||
@ -83,32 +42,51 @@
|
|||||||
|
|
||||||
{#if value}
|
{#if value}
|
||||||
<div class="flex-col flex-gap-3">
|
<div class="flex-col flex-gap-3">
|
||||||
{#each actionGroups as group}
|
<div class="flex-col flex-gap-1">
|
||||||
{#if group.actions.length > 0}
|
<Label label={plugin.string.AddToCard} />
|
||||||
<div class="flex-col flex-gap-1">
|
{#each topActions as action}
|
||||||
<Label label={group.label} />
|
<Button
|
||||||
{#each group.actions as action}
|
icon={action.icon}
|
||||||
{#if action.component}
|
label={action.label}
|
||||||
<Component is={action.component} props={{ object: value }}>
|
kind="no-border"
|
||||||
<slot />
|
justify="left"
|
||||||
</Component>
|
on:click={(e) => {
|
||||||
{:else}
|
invokeAction(value, e, action.action, action.actionProps)
|
||||||
<Button
|
}}
|
||||||
icon={action.icon}
|
/>
|
||||||
label={action.label}
|
{/each}
|
||||||
kind={action.kind ?? 'no-border'}
|
<Button
|
||||||
justify="left"
|
icon={plugin.icon.Card}
|
||||||
on:click={async (e) => {
|
label={plugin.string.Checklist}
|
||||||
if (action.handler) {
|
kind="no-border"
|
||||||
const handler = await getResource(action.handler)
|
justify="left"
|
||||||
handler(value, client, e)
|
on:click={(e) => {
|
||||||
}
|
showPopup(AddChecklist, { value }, getPopupAlignment(e))
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{/if}
|
<Button
|
||||||
{/each}
|
icon={IconAttachment}
|
||||||
</div>
|
label={plugin.string.Attachments}
|
||||||
{/if}
|
kind="no-border"
|
||||||
{/each}
|
justify="left"
|
||||||
|
on:click={(e) => {
|
||||||
|
showPopup(AttachmentPicker, { value }, getPopupAlignment(e))
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="flex-col flex-gap-1">
|
||||||
|
<Label label={plugin.string.Actions} />
|
||||||
|
{#each toolsActions as action}
|
||||||
|
<Button
|
||||||
|
icon={action.icon}
|
||||||
|
label={action.label}
|
||||||
|
kind="no-border"
|
||||||
|
justify="left"
|
||||||
|
on:click={(e) => {
|
||||||
|
invokeAction(value, e, action.action, action.actionProps)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -16,29 +16,24 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import attachment, { Attachment } from '@anticrm/attachment'
|
import attachment, { Attachment } from '@anticrm/attachment'
|
||||||
import type { Card } from '@anticrm/board'
|
import type { Card } from '@anticrm/board'
|
||||||
import { getResource } from '@anticrm/platform'
|
|
||||||
import { getClient } from '@anticrm/presentation'
|
import { getClient } from '@anticrm/presentation'
|
||||||
import { Button, Icon, IconAttachment, Label } from '@anticrm/ui'
|
import { Button, Icon, IconAttachment, Label, showPopup } from '@anticrm/ui'
|
||||||
|
import AttachmentPicker from '../popups/AttachmentPicker.svelte'
|
||||||
import AttachmentPresenter from '../presenters/AttachmentPresenter.svelte'
|
import AttachmentPresenter from '../presenters/AttachmentPresenter.svelte'
|
||||||
import board from '../../plugin'
|
import board from '../../plugin'
|
||||||
|
import { getPopupAlignment } from '../../utils/PopupUtils'
|
||||||
|
|
||||||
export let value: Card
|
export let value: Card
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
let attachments: Attachment[] = []
|
let attachments: Attachment[] = []
|
||||||
let addAttachment: (e: Event) => void
|
|
||||||
|
|
||||||
async function fetch () {
|
async function fetch () {
|
||||||
attachments = await client.findAll(attachment.class.Attachment, { space: value.space, attachedTo: value._id })
|
attachments = await client.findAll(attachment.class.Attachment, { space: value.space, attachedTo: value._id })
|
||||||
}
|
}
|
||||||
|
|
||||||
client.findOne(board.class.CardAction, { _id: board.cardAction.Attachments }).then(async (action) => {
|
function addAttachment (e: Event) {
|
||||||
if (action && action.handler) {
|
showPopup(AttachmentPicker, { object: value }, getPopupAlignment(e))
|
||||||
const handler = await getResource(action.handler)
|
}
|
||||||
addAttachment = (e) => {
|
|
||||||
handler(value, client, e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
$: value?.attachments && value.attachments > 0 && fetch()
|
$: value?.attachments && value.attachments > 0 && fetch()
|
||||||
</script>
|
</script>
|
||||||
|
@ -92,7 +92,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function showItemMenu (item: TodoItem, e?: Event) {
|
function showItemMenu (item: TodoItem, e?: Event) {
|
||||||
showPopup(ContextMenu, { object: item }, getPopupAlignment(e))
|
showPopup(ContextMenu, { object: item, baseMenuClass: board.class.Card }, getPopupAlignment(e))
|
||||||
}
|
}
|
||||||
|
|
||||||
$: checklistItemsQuery.query(task.class.TodoItem, { space: value.space, attachedTo: value._id }, (result) => {
|
$: checklistItemsQuery.query(task.class.TodoItem, { space: value.space, attachedTo: value._id }, (result) => {
|
||||||
|
@ -16,13 +16,15 @@
|
|||||||
import type { Card, CardDate } from '@anticrm/board'
|
import type { Card, CardDate } from '@anticrm/board'
|
||||||
|
|
||||||
import contact, { Employee } from '@anticrm/contact'
|
import contact, { Employee } from '@anticrm/contact'
|
||||||
import { getResource } from '@anticrm/platform'
|
import { Ref } from '@anticrm/core'
|
||||||
import { createQuery, getClient } from '@anticrm/presentation'
|
import { createQuery, getClient, UsersPopup } from '@anticrm/presentation'
|
||||||
import { Button, IconAdd, Label } from '@anticrm/ui'
|
import { Button, IconAdd, Label, showPopup } from '@anticrm/ui'
|
||||||
|
import { invokeAction } from '@anticrm/view-resources'
|
||||||
|
|
||||||
import board from '../../plugin'
|
import board from '../../plugin'
|
||||||
import { getCardActions } from '../../utils/CardActionUtils'
|
import { getCardActions } from '../../utils/CardActionUtils'
|
||||||
import { hasDate, updateCardMembers } from '../../utils/CardUtils'
|
import { hasDate, updateCardMembers } from '../../utils/CardUtils'
|
||||||
|
import { getPopupAlignment } from '../../utils/PopupUtils'
|
||||||
import DatePresenter from '../presenters/DatePresenter.svelte'
|
import DatePresenter from '../presenters/DatePresenter.svelte'
|
||||||
import MemberPresenter from '../presenters/MemberPresenter.svelte'
|
import MemberPresenter from '../presenters/MemberPresenter.svelte'
|
||||||
import CardLabels from './CardLabels.svelte'
|
import CardLabels from './CardLabels.svelte'
|
||||||
@ -30,20 +32,30 @@
|
|||||||
export let value: Card
|
export let value: Card
|
||||||
const query = createQuery()
|
const query = createQuery()
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
let members: Employee[]
|
let members: Employee[] = []
|
||||||
let membersHandler: (e: Event) => void
|
const membersHandler = (e?: Event) => {
|
||||||
|
showPopup(
|
||||||
|
UsersPopup,
|
||||||
|
{
|
||||||
|
_class: contact.class.Employee,
|
||||||
|
multiSelect: true,
|
||||||
|
allowDeselect: true,
|
||||||
|
selectedUsers: members?.map((m) => m._id) ?? [],
|
||||||
|
placeholder: board.string.SearchMembers
|
||||||
|
},
|
||||||
|
getPopupAlignment(e),
|
||||||
|
undefined,
|
||||||
|
(result: Array<Ref<Employee>>) => {
|
||||||
|
updateCardMembers(value, client, result)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
let dateHandler: (e: Event) => void
|
let dateHandler: (e: Event) => void
|
||||||
|
|
||||||
$: membersIds = members?.map((m) => m._id) ?? []
|
$: membersIds = members?.map((m) => m._id) ?? []
|
||||||
|
|
||||||
const getMenuItems = (member: Employee) => {
|
const getMenuItems = (member: Employee) => {
|
||||||
return [
|
return [
|
||||||
[
|
|
||||||
{
|
|
||||||
title: board.string.ViewProfile,
|
|
||||||
handler: () => console.log('TODO: implement')
|
|
||||||
}
|
|
||||||
],
|
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
title: board.string.RemoveFromCard,
|
title: board.string.RemoveFromCard,
|
||||||
@ -56,29 +68,20 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
$: if (value.members && value.members.length > 0) {
|
$: query.query(contact.class.Employee, { _id: { $in: value.members } }, (result) => {
|
||||||
query.query(contact.class.Employee, { _id: { $in: value.members } }, (result) => {
|
members = result
|
||||||
members = result
|
})
|
||||||
})
|
|
||||||
} else {
|
|
||||||
members = []
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateDate (e: CustomEvent<CardDate>) {
|
function updateDate (e: CustomEvent<CardDate>) {
|
||||||
client.update(value, { date: e.detail })
|
client.update(value, { date: e.detail })
|
||||||
}
|
}
|
||||||
|
|
||||||
getCardActions(client, {
|
getCardActions(client, {
|
||||||
_id: { $in: [board.cardAction.Dates, board.cardAction.Members] }
|
_id: { $in: [board.action.Dates] }
|
||||||
}).then(async (result) => {
|
}).then(async (result) => {
|
||||||
for (const action of result) {
|
for (const action of result) {
|
||||||
if (action.handler) {
|
if (action._id === board.action.Dates) {
|
||||||
const handler = await getResource(action.handler)
|
dateHandler = (e: Event) => invokeAction(value, e, action.action, action.actionProps)
|
||||||
if (action._id === board.cardAction.Dates) {
|
|
||||||
dateHandler = (e) => handler(value, client, e)
|
|
||||||
} else if (action._id === board.cardAction.Members) {
|
|
||||||
membersHandler = (e) => handler(value, client, e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -1,80 +0,0 @@
|
|||||||
<!--
|
|
||||||
// Copyright © 2022 Hardcore Engineering Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License. You may
|
|
||||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
//
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
-->
|
|
||||||
<script lang="ts">
|
|
||||||
import type { Card, CardAction } from '@anticrm/board'
|
|
||||||
import { getResource } from '@anticrm/platform'
|
|
||||||
import { getClient } from '@anticrm/presentation'
|
|
||||||
import { Button, Component } from '@anticrm/ui'
|
|
||||||
import { createEventDispatcher } from 'svelte'
|
|
||||||
|
|
||||||
import board from '../../plugin'
|
|
||||||
import { cardActionSorter, getCardActions } from '../../utils/CardActionUtils'
|
|
||||||
import { openCardPanel } from '../../utils/CardUtils'
|
|
||||||
|
|
||||||
export let value: Card
|
|
||||||
const client = getClient()
|
|
||||||
const dispatch = createEventDispatcher()
|
|
||||||
|
|
||||||
let actions: CardAction[] = []
|
|
||||||
|
|
||||||
function openCard () {
|
|
||||||
openCardPanel(value)
|
|
||||||
dispatch('close')
|
|
||||||
}
|
|
||||||
|
|
||||||
async function fetch () {
|
|
||||||
actions = []
|
|
||||||
const result = await getCardActions(client, { isInline: true })
|
|
||||||
for (const action of result) {
|
|
||||||
if (!action.supported) {
|
|
||||||
actions.push(action)
|
|
||||||
} else {
|
|
||||||
const supportedHandler = await getResource(action.supported)
|
|
||||||
if (supportedHandler(value, client)) {
|
|
||||||
actions.push(action)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
actions = actions.sort(cardActionSorter)
|
|
||||||
}
|
|
||||||
|
|
||||||
fetch()
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{#if value && !value.isArchived}
|
|
||||||
<div class="flex-col flex-gap-1">
|
|
||||||
<Button icon={board.icon.Card} label={board.string.OpenCard} kind="no-border" justify="left" on:click={openCard} />
|
|
||||||
{#each actions as action}
|
|
||||||
{#if action.component}
|
|
||||||
<Component is={action.component} props={{ object: value, isInline: true }}>
|
|
||||||
<slot />
|
|
||||||
</Component>
|
|
||||||
{:else}
|
|
||||||
<Button
|
|
||||||
icon={action.icon}
|
|
||||||
label={action.label}
|
|
||||||
kind="no-border"
|
|
||||||
justify="left"
|
|
||||||
on:click={async (e) => {
|
|
||||||
if (action.handler) {
|
|
||||||
const handler = await getResource(action.handler)
|
|
||||||
handler(value, client, e)
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{/if}
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
@ -15,10 +15,10 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Card, CardLabel, LabelsCompactMode } from '@anticrm/board'
|
import type { Card, CardLabel, LabelsCompactMode } from '@anticrm/board'
|
||||||
|
|
||||||
import { getResource } from '@anticrm/platform'
|
|
||||||
import preference from '@anticrm/preference'
|
import preference from '@anticrm/preference'
|
||||||
import { createQuery, getClient } from '@anticrm/presentation'
|
import { createQuery, getClient } from '@anticrm/presentation'
|
||||||
import { Button, IconAdd } from '@anticrm/ui'
|
import { Button, IconAdd } from '@anticrm/ui'
|
||||||
|
import { invokeAction } from '@anticrm/view-resources'
|
||||||
|
|
||||||
import board from '../../plugin'
|
import board from '../../plugin'
|
||||||
import { getCardActions } from '../../utils/CardActionUtils'
|
import { getCardActions } from '../../utils/CardActionUtils'
|
||||||
@ -50,11 +50,10 @@
|
|||||||
|
|
||||||
if (!isInline) {
|
if (!isInline) {
|
||||||
getCardActions(client, {
|
getCardActions(client, {
|
||||||
_id: board.cardAction.Labels
|
_id: board.action.Labels
|
||||||
}).then(async (result) => {
|
}).then(async (result) => {
|
||||||
if (result?.[0]?.handler) {
|
if (result?.[0]) {
|
||||||
const handler = await getResource(result[0].handler)
|
labelsHandler = (e: Event) => invokeAction(value, e, result[0].action, result[0].actionProps)
|
||||||
labelsHandler = (e: Event) => handler(value, client, e)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
import board from '../../plugin'
|
import board from '../../plugin'
|
||||||
|
|
||||||
export let object: Card
|
export let value: Card
|
||||||
|
|
||||||
const noneListItem: ListItem = {
|
const noneListItem: ListItem = {
|
||||||
_id: 'none',
|
_id: 'none',
|
||||||
@ -43,9 +43,9 @@
|
|||||||
const items: TodoItem[] = template ? await client.findAll(task.class.TodoItem, { attachedTo: template._id }) : []
|
const items: TodoItem[] = template ? await client.findAll(task.class.TodoItem, { attachedTo: template._id }) : []
|
||||||
const checklistRef = await client.addCollection(
|
const checklistRef = await client.addCollection(
|
||||||
task.class.TodoItem,
|
task.class.TodoItem,
|
||||||
object.space,
|
value.space,
|
||||||
object._id,
|
value._id,
|
||||||
object._class,
|
value._class,
|
||||||
'todoItems',
|
'todoItems',
|
||||||
{
|
{
|
||||||
name,
|
name,
|
||||||
@ -57,7 +57,7 @@
|
|||||||
if (items.length > 0) {
|
if (items.length > 0) {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
items.map((item) =>
|
items.map((item) =>
|
||||||
client.addCollection(task.class.TodoItem, object.space, checklistRef, task.class.TodoItem, 'items', {
|
client.addCollection(task.class.TodoItem, value.space, checklistRef, task.class.TodoItem, 'items', {
|
||||||
name: item.name,
|
name: item.name,
|
||||||
dueTo: item.dueTo,
|
dueTo: item.dueTo,
|
||||||
done: item.done,
|
done: item.done,
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
import board from '../../plugin'
|
import board from '../../plugin'
|
||||||
|
|
||||||
export let object: Card
|
export let value: Card
|
||||||
|
|
||||||
let inputFile: HTMLInputElement
|
let inputFile: HTMLInputElement
|
||||||
let loading: number = 0
|
let loading: number = 0
|
||||||
@ -36,9 +36,9 @@
|
|||||||
<AddAttachment
|
<AddAttachment
|
||||||
bind:inputFile
|
bind:inputFile
|
||||||
bind:loading
|
bind:loading
|
||||||
objectClass={object._class}
|
objectClass={value._class}
|
||||||
objectId={object._id}
|
objectId={value._id}
|
||||||
space={object.space}
|
space={value.space}
|
||||||
on:attached={onAttached}
|
on:attached={onAttached}
|
||||||
>
|
>
|
||||||
<svelte:fragment slot="control" let:click>
|
<svelte:fragment slot="control" let:click>
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
import board from '../../plugin'
|
import board from '../../plugin'
|
||||||
import { getBoardAvailableColors } from '../../utils/BoardUtils'
|
import { getBoardAvailableColors } from '../../utils/BoardUtils'
|
||||||
import ColorPresenter from '../presenters/ColorPresenter.svelte'
|
import ColorPresenter from '../presenters/ColorPresenter.svelte'
|
||||||
export let object: Card
|
export let value: Card
|
||||||
|
|
||||||
let cover = object.cover
|
let cover = value.cover
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
function updateCover (newCover?: Partial<CardCover>) {
|
function updateCover (newCover?: Partial<CardCover>) {
|
||||||
cover = newCover ? { size: 'small', ...cover, ...newCover } : null
|
cover = newCover ? { size: 'small', ...cover, ...newCover } : null
|
||||||
client.update(object, { cover })
|
client.update(value, { cover })
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
import CardLabelsEditor from './CardLabelsEditor.svelte'
|
import CardLabelsEditor from './CardLabelsEditor.svelte'
|
||||||
import CardLabelsPicker from './CardLabelsPicker.svelte'
|
import CardLabelsPicker from './CardLabelsPicker.svelte'
|
||||||
|
|
||||||
export let object: Card
|
export let value: Card
|
||||||
|
|
||||||
let editMode: {
|
let editMode: {
|
||||||
isEdit?: boolean
|
isEdit?: boolean
|
||||||
@ -19,7 +19,7 @@
|
|||||||
{#if editMode.isEdit}
|
{#if editMode.isEdit}
|
||||||
<CardLabelsEditor
|
<CardLabelsEditor
|
||||||
on:close
|
on:close
|
||||||
boardRef={object.space}
|
boardRef={value.space}
|
||||||
object={editMode.object}
|
object={editMode.object}
|
||||||
onBack={() => setEditMode(false, undefined)}
|
onBack={() => setEditMode(false, undefined)}
|
||||||
/>
|
/>
|
||||||
@ -27,7 +27,7 @@
|
|||||||
<CardLabelsPicker
|
<CardLabelsPicker
|
||||||
bind:search
|
bind:search
|
||||||
on:close
|
on:close
|
||||||
{object}
|
object={value}
|
||||||
onCreate={() => setEditMode(true, undefined)}
|
onCreate={() => setEditMode(true, undefined)}
|
||||||
onEdit={(o) => setEditMode(true, o)}
|
onEdit={(o) => setEditMode(true, o)}
|
||||||
/>
|
/>
|
||||||
|
@ -3,30 +3,30 @@
|
|||||||
import { Label, Button, Status as StatusControl, TextArea } from '@anticrm/ui'
|
import { Label, Button, Status as StatusControl, TextArea } from '@anticrm/ui'
|
||||||
import { Class, Client, Doc, Ref } from '@anticrm/core'
|
import { Class, Client, Doc, Ref } from '@anticrm/core'
|
||||||
import { getResource, OK, Resource, Status } from '@anticrm/platform'
|
import { getResource, OK, Resource, Status } from '@anticrm/platform'
|
||||||
|
import { getClient } from '@anticrm/presentation'
|
||||||
import { Card } from '@anticrm/board'
|
import { Card } from '@anticrm/board'
|
||||||
import view from '@anticrm/view'
|
import view from '@anticrm/view'
|
||||||
import board from '../../plugin'
|
import board from '../../plugin'
|
||||||
import SpaceSelect from '../selectors/SpaceSelect.svelte'
|
import SpaceSelect from '../selectors/SpaceSelect.svelte'
|
||||||
import StateSelect from '../selectors/StateSelect.svelte'
|
import StateSelect from '../selectors/StateSelect.svelte'
|
||||||
import RankSelect from '../selectors/RankSelect.svelte'
|
import RankSelect from '../selectors/RankSelect.svelte'
|
||||||
import type { TxOperations } from '@anticrm/core'
|
|
||||||
import { generateId, AttachedData } from '@anticrm/core'
|
import { generateId, AttachedData } from '@anticrm/core'
|
||||||
import task from '@anticrm/task'
|
import task from '@anticrm/task'
|
||||||
import { createMissingLabels } from '../../utils/BoardUtils'
|
import { createMissingLabels } from '../../utils/BoardUtils'
|
||||||
|
|
||||||
export let object: Card
|
export let value: Card
|
||||||
export let client: TxOperations
|
const client = getClient()
|
||||||
|
|
||||||
const hierarchy = client.getHierarchy()
|
const hierarchy = client.getHierarchy()
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
let inputRef: TextArea
|
let inputRef: TextArea
|
||||||
let title = object.title
|
let title = value.title
|
||||||
let status: Status = OK
|
let status: Status = OK
|
||||||
const selected = {
|
const selected = {
|
||||||
space: object.space,
|
space: value.space,
|
||||||
state: object.state,
|
state: value.state,
|
||||||
rank: object.rank
|
rank: value.rank
|
||||||
}
|
}
|
||||||
|
|
||||||
async function copyCard (): Promise<void> {
|
async function copyCard (): Promise<void> {
|
||||||
@ -40,9 +40,9 @@
|
|||||||
const incResult = await client.update(sequence, { $inc: { sequence: 1 } }, true)
|
const incResult = await client.update(sequence, { $inc: { sequence: 1 } }, true)
|
||||||
|
|
||||||
const labels =
|
const labels =
|
||||||
object.space !== selected.space ? await createMissingLabels(client, object, selected.space) : object.labels
|
value.space !== selected.space ? await createMissingLabels(client, value, selected.space) : value.labels
|
||||||
|
|
||||||
const value: AttachedData<Card> = {
|
const copy: AttachedData<Card> = {
|
||||||
state: selected.state,
|
state: selected.state,
|
||||||
doneState: null,
|
doneState: null,
|
||||||
number: (incResult as any).object.sequence,
|
number: (incResult as any).object.sequence,
|
||||||
@ -61,7 +61,7 @@
|
|||||||
selected.space,
|
selected.space,
|
||||||
board.class.Board,
|
board.class.Board,
|
||||||
'cards',
|
'cards',
|
||||||
value,
|
copy,
|
||||||
newCardId
|
newCardId
|
||||||
)
|
)
|
||||||
dispatch('close')
|
dispatch('close')
|
||||||
@ -71,7 +71,7 @@
|
|||||||
action: Resource<<T extends Doc>(doc: T, client: Client) => Promise<Status>>
|
action: Resource<<T extends Doc>(doc: T, client: Client) => Promise<Status>>
|
||||||
): Promise<Status> {
|
): Promise<Status> {
|
||||||
const impl = await getResource(action)
|
const impl = await getResource(action)
|
||||||
return await impl(object, client)
|
return await impl(value, client)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function validate (doc: Doc, _class: Ref<Class<Doc>>): Promise<void> {
|
async function validate (doc: Doc, _class: Ref<Class<Doc>>): Promise<void> {
|
||||||
@ -86,7 +86,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$: validate({ ...object, ...selected }, object._class)
|
$: validate({ ...value, ...selected }, value._class)
|
||||||
|
|
||||||
onMount(() => inputRef.focus())
|
onMount(() => inputRef.focus())
|
||||||
</script>
|
</script>
|
||||||
@ -109,20 +109,20 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="ap-category">
|
<div class="ap-category">
|
||||||
<div class="categoryItem w-full border-radius-2 p-2 background-button-bg-enabled">
|
<div class="categoryItem w-full border-radius-2 p-2 background-button-bg-enabled">
|
||||||
<SpaceSelect label={board.string.Board} {object} bind:selected={selected.space} />
|
<SpaceSelect label={board.string.Board} object={value} bind:selected={selected.space} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ap-category flex-gap-3">
|
<div class="ap-category flex-gap-3">
|
||||||
<div class="categoryItem w-full border-radius-2 p-2 background-button-bg-enabled">
|
<div class="categoryItem w-full border-radius-2 p-2 background-button-bg-enabled">
|
||||||
{#key selected.space}
|
{#key selected.space}
|
||||||
<StateSelect label={board.string.List} {object} space={selected.space} bind:selected={selected.state} />
|
<StateSelect label={board.string.List} object={value} space={selected.space} bind:selected={selected.state} />
|
||||||
{/key}
|
{/key}
|
||||||
</div>
|
</div>
|
||||||
<div class="categoryItem w-full border-radius-2 p-2 background-button-bg-enabled">
|
<div class="categoryItem w-full border-radius-2 p-2 background-button-bg-enabled">
|
||||||
{#key selected.state}
|
{#key selected.state}
|
||||||
<RankSelect
|
<RankSelect
|
||||||
label={board.string.Position}
|
label={board.string.Position}
|
||||||
{object}
|
object={value}
|
||||||
state={selected.state}
|
state={selected.state}
|
||||||
bind:selected={selected.rank}
|
bind:selected={selected.rank}
|
||||||
isCopying={true}
|
isCopying={true}
|
||||||
|
@ -6,29 +6,29 @@
|
|||||||
import board from '../../plugin'
|
import board from '../../plugin'
|
||||||
import { getClient } from '@anticrm/presentation'
|
import { getClient } from '@anticrm/presentation'
|
||||||
|
|
||||||
export let object: Card
|
export let value: Card
|
||||||
|
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
let startDate = object.date?.startDate
|
let startDate = value.date?.startDate
|
||||||
let savedStartDate = object.date?.startDate ?? Date.now()
|
let savedStartDate = value.date?.startDate ?? Date.now()
|
||||||
let startDateEnabled = startDate !== undefined
|
let startDateEnabled = startDate !== undefined
|
||||||
$: startDate && (savedStartDate = startDate)
|
$: startDate && (savedStartDate = startDate)
|
||||||
let dueDate = object.date?.dueDate
|
let dueDate = value.date?.dueDate
|
||||||
let savedDueDate = object.date?.dueDate ?? Date.now()
|
let savedDueDate = value.date?.dueDate ?? Date.now()
|
||||||
let dueDateEnabled = dueDate !== undefined
|
let dueDateEnabled = dueDate !== undefined
|
||||||
$: dueDate && (savedDueDate = dueDate)
|
$: dueDate && (savedDueDate = dueDate)
|
||||||
|
|
||||||
function getEmptyDate (): CardDate {
|
function getEmptyDate (): CardDate {
|
||||||
return { _class: object.date?._class ?? board.class.CardDate }
|
return { _class: value.date?._class ?? board.class.CardDate }
|
||||||
}
|
}
|
||||||
|
|
||||||
function update () {
|
function update () {
|
||||||
const date: CardDate = getEmptyDate()
|
const date: CardDate = getEmptyDate()
|
||||||
if (startDate !== undefined) date.startDate = startDate
|
if (startDate !== undefined) date.startDate = startDate
|
||||||
if (dueDate !== undefined) date.dueDate = dueDate
|
if (dueDate !== undefined) date.dueDate = dueDate
|
||||||
client.update(object, { date })
|
client.update(value, { date })
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -82,7 +82,7 @@
|
|||||||
label={board.string.Remove}
|
label={board.string.Remove}
|
||||||
size={'small'}
|
size={'small'}
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
client.update(object, { date: getEmptyDate() })
|
client.update(value, { date: getEmptyDate() })
|
||||||
dispatch('close')
|
dispatch('close')
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@ -96,7 +96,7 @@
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div class="flex-center mr-2">
|
<div class="flex-center mr-2">
|
||||||
<Component is={calendar.component.DocReminder} props={{ value: object }} />
|
<Component is={calendar.component.DocReminder} props={{ value }} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -12,29 +12,29 @@
|
|||||||
import RankSelect from '../selectors/RankSelect.svelte'
|
import RankSelect from '../selectors/RankSelect.svelte'
|
||||||
import { createMissingLabels } from '../../utils/BoardUtils'
|
import { createMissingLabels } from '../../utils/BoardUtils'
|
||||||
|
|
||||||
export let object: Card
|
export let value: Card
|
||||||
|
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
const hierarchy = client.getHierarchy()
|
const hierarchy = client.getHierarchy()
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
let status: Status = OK
|
let status: Status = OK
|
||||||
const selected = {
|
const selected = {
|
||||||
space: object.space,
|
space: value.space,
|
||||||
state: object.state,
|
state: value.state,
|
||||||
rank: object.rank
|
rank: value.rank
|
||||||
}
|
}
|
||||||
|
|
||||||
async function move (): Promise<void> {
|
async function move (): Promise<void> {
|
||||||
const update: DocumentUpdate<Card> = {}
|
const update: DocumentUpdate<Card> = {}
|
||||||
|
|
||||||
if (selected.space !== object.space) {
|
if (selected.space !== value.space) {
|
||||||
update.labels = await createMissingLabels(client, object, selected.space)
|
update.labels = await createMissingLabels(client, value, selected.space)
|
||||||
update.space = selected.space
|
update.space = selected.space
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selected.state !== object.state) update.state = selected.state
|
if (selected.state !== value.state) update.state = selected.state
|
||||||
if (selected.rank !== object.rank) update.rank = selected.rank
|
if (selected.rank !== value.rank) update.rank = selected.rank
|
||||||
client.update(object, update)
|
client.update(value, update)
|
||||||
dispatch('close')
|
dispatch('close')
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,7 +42,7 @@
|
|||||||
action: Resource<<T extends Doc>(doc: T, client: Client) => Promise<Status>>
|
action: Resource<<T extends Doc>(doc: T, client: Client) => Promise<Status>>
|
||||||
): Promise<Status> {
|
): Promise<Status> {
|
||||||
const impl = await getResource(action)
|
const impl = await getResource(action)
|
||||||
return await impl(object, client)
|
return await impl(value, client)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function validate (doc: Doc, _class: Ref<Class<Doc>>): Promise<void> {
|
async function validate (doc: Doc, _class: Ref<Class<Doc>>): Promise<void> {
|
||||||
@ -57,7 +57,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$: validate({ ...object, ...selected }, object._class)
|
$: validate({ ...value, ...selected }, value._class)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="antiPopup antiPopup-withHeader antiPopup-withTitle antiPopup-withCategory w-85">
|
<div class="antiPopup antiPopup-withHeader antiPopup-withTitle antiPopup-withCategory w-85">
|
||||||
@ -72,18 +72,18 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="ap-category">
|
<div class="ap-category">
|
||||||
<div class="categoryItem w-full border-radius-2 p-2 background-button-bg-enabled">
|
<div class="categoryItem w-full border-radius-2 p-2 background-button-bg-enabled">
|
||||||
<SpaceSelect label={board.string.Board} {object} bind:selected={selected.space} />
|
<SpaceSelect label={board.string.Board} object={value} bind:selected={selected.space} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ap-category flex-gap-3">
|
<div class="ap-category flex-gap-3">
|
||||||
<div class="categoryItem w-full border-radius-2 p-2 background-button-bg-enabled">
|
<div class="categoryItem w-full border-radius-2 p-2 background-button-bg-enabled">
|
||||||
{#key selected.space}
|
{#key selected.space}
|
||||||
<StateSelect label={board.string.List} {object} space={selected.space} bind:selected={selected.state} />
|
<StateSelect label={board.string.List} object={value} space={selected.space} bind:selected={selected.state} />
|
||||||
{/key}
|
{/key}
|
||||||
</div>
|
</div>
|
||||||
<div class="categoryItem w-full border-radius-2 p-2 background-button-bg-enabled">
|
<div class="categoryItem w-full border-radius-2 p-2 background-button-bg-enabled">
|
||||||
{#key selected.state}
|
{#key selected.state}
|
||||||
<RankSelect label={board.string.Position} {object} state={selected.state} bind:selected={selected.rank} />
|
<RankSelect label={board.string.Position} object={value} state={selected.state} bind:selected={selected.rank} />
|
||||||
{/key}
|
{/key}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -98,7 +98,7 @@
|
|||||||
<Button
|
<Button
|
||||||
label={board.string.Move}
|
label={board.string.Move}
|
||||||
size={'small'}
|
size={'small'}
|
||||||
disabled={status !== OK || (object.state === selected.state && object.rank === selected.rank)}
|
disabled={status !== OK || (value.state === selected.state && value.rank === selected.rank)}
|
||||||
kind={'primary'}
|
kind={'primary'}
|
||||||
on:click={move}
|
on:click={move}
|
||||||
/>
|
/>
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import { createEventDispatcher } from 'svelte'
|
|
||||||
import { Label, Button, ActionIcon, IconClose } from '@anticrm/ui'
|
|
||||||
import board from '../../plugin'
|
|
||||||
import { getClient } from '@anticrm/presentation'
|
|
||||||
import { Card } from '@anticrm/board'
|
|
||||||
|
|
||||||
export let object: Card
|
|
||||||
|
|
||||||
const client = getClient()
|
|
||||||
const dispatch = createEventDispatcher()
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="antiPopup antiPopup-withHeader antiPopup-withTitle antiPopup-withCategory w-85">
|
|
||||||
<div class="ap-space" />
|
|
||||||
<div class="flex-row-center header">
|
|
||||||
<div class="flex-center flex-grow">
|
|
||||||
<Label label={board.string.Delete} />
|
|
||||||
</div>
|
|
||||||
<div class="close-icon mr-1">
|
|
||||||
<ActionIcon
|
|
||||||
icon={IconClose}
|
|
||||||
size={'small'}
|
|
||||||
action={() => {
|
|
||||||
dispatch('close')
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="ap-space bottom-divider" />
|
|
||||||
<div class="ap-box ml-4 mr-4 mt-4">
|
|
||||||
<Label label={board.string.DeleteCard} />
|
|
||||||
</div>
|
|
||||||
<div class="ap-footer">
|
|
||||||
<Button
|
|
||||||
size={'small'}
|
|
||||||
width="100%"
|
|
||||||
label={board.string.Delete}
|
|
||||||
kind={'dangerous'}
|
|
||||||
on:click={() => {
|
|
||||||
client.remove(object)
|
|
||||||
dispatch('close')
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@ -13,12 +13,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
import type { Card } from '@anticrm/board'
|
|
||||||
import contact, { Employee } from '@anticrm/contact'
|
|
||||||
import type { TxOperations as Client, Ref } from '@anticrm/core'
|
|
||||||
import { Resources } from '@anticrm/platform'
|
import { Resources } from '@anticrm/platform'
|
||||||
import { UsersPopup } from '@anticrm/presentation'
|
|
||||||
import { showPopup } from '@anticrm/ui'
|
|
||||||
|
|
||||||
import BoardPresenter from './components/BoardPresenter.svelte'
|
import BoardPresenter from './components/BoardPresenter.svelte'
|
||||||
import CardPresenter from './components/CardPresenter.svelte'
|
import CardPresenter from './components/CardPresenter.svelte'
|
||||||
@ -27,11 +22,8 @@ import CreateCard from './components/CreateCard.svelte'
|
|||||||
import EditCard from './components/EditCard.svelte'
|
import EditCard from './components/EditCard.svelte'
|
||||||
import KanbanCard from './components/KanbanCard.svelte'
|
import KanbanCard from './components/KanbanCard.svelte'
|
||||||
import KanbanView from './components/KanbanView.svelte'
|
import KanbanView from './components/KanbanView.svelte'
|
||||||
import AddChecklist from './components/popups/AddChecklist.svelte'
|
|
||||||
import AttachmentPicker from './components/popups/AttachmentPicker.svelte'
|
|
||||||
import CardLabelsPopup from './components/popups/CardLabelsPopup.svelte'
|
import CardLabelsPopup from './components/popups/CardLabelsPopup.svelte'
|
||||||
import MoveCard from './components/popups/MoveCard.svelte'
|
import MoveCard from './components/popups/MoveCard.svelte'
|
||||||
import DeleteCard from './components/popups/RemoveCard.svelte'
|
|
||||||
import CopyCard from './components/popups/CopyCard.svelte'
|
import CopyCard from './components/popups/CopyCard.svelte'
|
||||||
import DateRangePicker from './components/popups/DateRangePicker.svelte'
|
import DateRangePicker from './components/popups/DateRangePicker.svelte'
|
||||||
import CardDatePresenter from './components/presenters/DatePresenter.svelte'
|
import CardDatePresenter from './components/presenters/DatePresenter.svelte'
|
||||||
@ -44,69 +36,8 @@ import Archive from './components/Archive.svelte'
|
|||||||
import TableView from './components/TableView.svelte'
|
import TableView from './components/TableView.svelte'
|
||||||
import UserBoxList from './components/UserBoxList.svelte'
|
import UserBoxList from './components/UserBoxList.svelte'
|
||||||
import CardLabels from './components/editor/CardLabels.svelte'
|
import CardLabels from './components/editor/CardLabels.svelte'
|
||||||
import board from './plugin'
|
|
||||||
import {
|
|
||||||
addCurrentUser,
|
|
||||||
canAddCurrentUser,
|
|
||||||
isArchived,
|
|
||||||
isUnarchived,
|
|
||||||
archiveCard,
|
|
||||||
unarchiveCard,
|
|
||||||
updateCardMembers
|
|
||||||
} from './utils/CardUtils'
|
|
||||||
import { getPopupAlignment } from './utils/PopupUtils'
|
|
||||||
import CardCoverEditor from './components/popups/CardCoverEditor.svelte'
|
import CardCoverEditor from './components/popups/CardCoverEditor.svelte'
|
||||||
|
|
||||||
async function showMoveCardPopup (object: Card, client: Client, e?: Event): Promise<void> {
|
|
||||||
showPopup(MoveCard, { object }, getPopupAlignment(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
async function showDeleteCardPopup (object: Card, client: Client, e?: Event): Promise<void> {
|
|
||||||
showPopup(DeleteCard, { object }, getPopupAlignment(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
async function showCopyCardPopup (object: Card, client: Client, e?: Event): Promise<void> {
|
|
||||||
showPopup(CopyCard, { object, client }, getPopupAlignment(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
async function showDatePickerPopup (object: Card, client: Client, e?: Event): Promise<void> {
|
|
||||||
showPopup(DateRangePicker, { object }, getPopupAlignment(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
async function showCardLabelsPopup (object: Card, client: Client, e?: Event): Promise<void> {
|
|
||||||
showPopup(CardLabelsPopup, { object }, getPopupAlignment(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
async function showChecklistsPopup (object: Card, client: Client, e?: Event): Promise<void> {
|
|
||||||
showPopup(AddChecklist, { object }, getPopupAlignment(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
async function showEditMembersPopup (object: Card, client: Client, e?: Event): Promise<void> {
|
|
||||||
showPopup(
|
|
||||||
UsersPopup,
|
|
||||||
{
|
|
||||||
_class: contact.class.Employee,
|
|
||||||
multiSelect: true,
|
|
||||||
allowDeselect: true,
|
|
||||||
selectedUsers: object?.members ?? [],
|
|
||||||
placeholder: board.string.SearchMembers
|
|
||||||
},
|
|
||||||
getPopupAlignment(e),
|
|
||||||
undefined,
|
|
||||||
(result: Array<Ref<Employee>>) => {
|
|
||||||
updateCardMembers(object, client, result)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function showAttachmentsPopup (object: Card, client: Client, e?: Event): Promise<void> {
|
|
||||||
showPopup(AttachmentPicker, { object }, getPopupAlignment(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
async function showCoverPopup (object: Card, client: Client, e?: Event): Promise<void> {
|
|
||||||
showPopup(CardCoverEditor, { object }, getPopupAlignment(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
export default async (): Promise<Resources> => ({
|
export default async (): Promise<Resources> => ({
|
||||||
component: {
|
component: {
|
||||||
CreateBoard,
|
CreateBoard,
|
||||||
@ -125,26 +56,12 @@ export default async (): Promise<Resources> => ({
|
|||||||
MenuMainPage,
|
MenuMainPage,
|
||||||
TableView,
|
TableView,
|
||||||
UserBoxList,
|
UserBoxList,
|
||||||
CardLabels
|
CardLabels,
|
||||||
},
|
// action popups
|
||||||
cardActionHandler: {
|
LabelsActionPopup: CardLabelsPopup,
|
||||||
Join: addCurrentUser,
|
DatesActionPopup: DateRangePicker,
|
||||||
Move: showMoveCardPopup,
|
CoverActionPopup: CardCoverEditor,
|
||||||
Dates: showDatePickerPopup,
|
MoveActionPopup: MoveCard,
|
||||||
Labels: showCardLabelsPopup,
|
CopyActionPopup: CopyCard
|
||||||
Attachments: showAttachmentsPopup,
|
|
||||||
Archive: archiveCard,
|
|
||||||
SendToBoard: unarchiveCard,
|
|
||||||
Delete: showDeleteCardPopup,
|
|
||||||
Members: showEditMembersPopup,
|
|
||||||
Checklist: showChecklistsPopup,
|
|
||||||
Copy: showCopyCardPopup,
|
|
||||||
Cover: showCoverPopup
|
|
||||||
},
|
|
||||||
cardActionSupportedHandler: {
|
|
||||||
Join: canAddCurrentUser,
|
|
||||||
Archive: isUnarchived,
|
|
||||||
SendToBoard: isArchived,
|
|
||||||
Delete: isArchived
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
import { CardAction } from '@anticrm/board'
|
import type { Action } from '@anticrm/view'
|
||||||
|
import view from '@anticrm/view'
|
||||||
import { Client, DocumentQuery } from '@anticrm/core'
|
import { Client, DocumentQuery } from '@anticrm/core'
|
||||||
|
|
||||||
import board from '../plugin'
|
export const getCardActions = async (client: Client, query?: DocumentQuery<Action>): Promise<Action[]> => {
|
||||||
|
return await client.findAll(view.class.Action, query ?? {})
|
||||||
export const cardActionSorter = (a1: CardAction, a2: CardAction): number => a1.position - a2.position
|
|
||||||
|
|
||||||
export const getCardActions = async (client: Client, query?: DocumentQuery<CardAction>): Promise<CardAction[]> => {
|
|
||||||
return await client.findAll(board.class.CardAction, query ?? {})
|
|
||||||
}
|
}
|
||||||
|
@ -15,12 +15,13 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import { Employee } from '@anticrm/contact'
|
import { Employee } from '@anticrm/contact'
|
||||||
import type { AttachedDoc, Class, TxOperations as Client, Doc, Markup, Ref, Timestamp, Obj } from '@anticrm/core'
|
import type { AttachedDoc, Class, Doc, Markup, Ref, Timestamp, Obj } from '@anticrm/core'
|
||||||
import type { Asset, IntlString, Plugin, Resource } from '@anticrm/platform'
|
import type { Asset, IntlString, Plugin } from '@anticrm/platform'
|
||||||
import { plugin } from '@anticrm/platform'
|
import { plugin } from '@anticrm/platform'
|
||||||
|
import type { Preference } from '@anticrm/preference'
|
||||||
import type { KanbanTemplateSpace, SpaceWithStates, Task } from '@anticrm/task'
|
import type { KanbanTemplateSpace, SpaceWithStates, Task } from '@anticrm/task'
|
||||||
import type { AnyComponent } from '@anticrm/ui'
|
import type { AnyComponent } from '@anticrm/ui'
|
||||||
import type { Preference } from '@anticrm/preference'
|
import { Action, ActionCategory } from '@anticrm/view'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
@ -88,21 +89,7 @@ export interface Card extends Task {
|
|||||||
comments?: number
|
comments?: number
|
||||||
attachments?: number
|
attachments?: number
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* @public
|
|
||||||
*/
|
|
||||||
export interface CardAction extends Doc {
|
|
||||||
component?: AnyComponent
|
|
||||||
hint?: IntlString
|
|
||||||
icon: Asset
|
|
||||||
isInline?: boolean
|
|
||||||
kind?: 'primary' | 'secondary' | 'no-border' | 'transparent' | 'dangerous'
|
|
||||||
label: IntlString
|
|
||||||
position: number
|
|
||||||
type: string
|
|
||||||
handler?: Resource<(card: Card, client: Client, e?: Event) => void>
|
|
||||||
supported?: Resource<(card: Card, client: Client) => boolean>
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
@ -133,12 +120,24 @@ const boards = plugin(boardId, {
|
|||||||
class: {
|
class: {
|
||||||
Board: '' as Ref<Class<Board>>,
|
Board: '' as Ref<Class<Board>>,
|
||||||
Card: '' as Ref<Class<Card>>,
|
Card: '' as Ref<Class<Card>>,
|
||||||
CardAction: '' as Ref<Class<CardAction>>,
|
|
||||||
CardDate: '' as Ref<Class<CardDate>>,
|
CardDate: '' as Ref<Class<CardDate>>,
|
||||||
CardLabel: '' as Ref<Class<CardLabel>>,
|
CardLabel: '' as Ref<Class<CardLabel>>,
|
||||||
MenuPage: '' as Ref<Class<MenuPage>>,
|
MenuPage: '' as Ref<Class<MenuPage>>,
|
||||||
LabelsCompactMode: '' as Ref<Class<LabelsCompactMode>>
|
LabelsCompactMode: '' as Ref<Class<LabelsCompactMode>>
|
||||||
},
|
},
|
||||||
|
category: {
|
||||||
|
Card: '' as Ref<ActionCategory>
|
||||||
|
},
|
||||||
|
action: {
|
||||||
|
Cover: '' as Ref<Action>,
|
||||||
|
Dates: '' as Ref<Action>,
|
||||||
|
Labels: '' as Ref<Action>,
|
||||||
|
Move: '' as Ref<Action>,
|
||||||
|
Copy: '' as Ref<Action>,
|
||||||
|
Archive: '' as Ref<Action>,
|
||||||
|
SendToBoard: '' as Ref<Action>,
|
||||||
|
Delete: '' as Ref<Action>
|
||||||
|
},
|
||||||
icon: {
|
icon: {
|
||||||
Board: '' as Asset,
|
Board: '' as Asset,
|
||||||
Card: '' as Asset
|
Card: '' as Asset
|
||||||
@ -149,56 +148,6 @@ const boards = plugin(boardId, {
|
|||||||
menuPageId: {
|
menuPageId: {
|
||||||
Main: 'main',
|
Main: 'main',
|
||||||
Archive: 'archive'
|
Archive: 'archive'
|
||||||
},
|
|
||||||
cardActionType: {
|
|
||||||
Suggested: 'Suggested',
|
|
||||||
Editor: 'Editor',
|
|
||||||
Cover: 'Cover',
|
|
||||||
AddToCard: 'AddToCard',
|
|
||||||
Automation: 'Automation',
|
|
||||||
Action: 'Action'
|
|
||||||
},
|
|
||||||
cardAction: {
|
|
||||||
Cover: '' as Ref<CardAction>,
|
|
||||||
Join: '' as Ref<CardAction>,
|
|
||||||
Members: '' as Ref<CardAction>,
|
|
||||||
Labels: '' as Ref<CardAction>,
|
|
||||||
Checklist: '' as Ref<CardAction>,
|
|
||||||
Dates: '' as Ref<CardAction>,
|
|
||||||
Attachments: '' as Ref<CardAction>,
|
|
||||||
CustomFields: '' as Ref<CardAction>,
|
|
||||||
AddButton: '' as Ref<CardAction>,
|
|
||||||
Move: '' as Ref<CardAction>,
|
|
||||||
Copy: '' as Ref<CardAction>,
|
|
||||||
MakeTemplate: '' as Ref<CardAction>,
|
|
||||||
Watch: '' as Ref<CardAction>,
|
|
||||||
Archive: '' as Ref<CardAction>,
|
|
||||||
SendToBoard: '' as Ref<CardAction>,
|
|
||||||
Delete: '' as Ref<CardAction>
|
|
||||||
},
|
|
||||||
cardActionHandler: {
|
|
||||||
Cover: '' as Resource<(card: Card, client: Client, e?: Event) => void>,
|
|
||||||
Join: '' as Resource<(card: Card, client: Client, e?: Event) => void>,
|
|
||||||
Members: '' as Resource<(card: Card, client: Client, e?: Event) => void>,
|
|
||||||
Labels: '' as Resource<(card: Card, client: Client, e?: Event) => void>,
|
|
||||||
Checklist: '' as Resource<(card: Card, client: Client, e?: Event) => void>,
|
|
||||||
Dates: '' as Resource<(card: Card, client: Client, e?: Event) => void>,
|
|
||||||
Attachments: '' as Resource<(card: Card, client: Client, e?: Event) => void>,
|
|
||||||
CustomFields: '' as Resource<(card: Card, client: Client, e?: Event) => void>,
|
|
||||||
AddButton: '' as Resource<(card: Card, client: Client, e?: Event) => void>,
|
|
||||||
Move: '' as Resource<(card: Card, client: Client, e?: Event) => void>,
|
|
||||||
Copy: '' as Resource<(card: Card, client: Client, e?: Event) => void>,
|
|
||||||
MakeTemplate: '' as Resource<(card: Card, client: Client, e?: Event) => void>,
|
|
||||||
Watch: '' as Resource<(card: Card, client: Client, e?: Event) => void>,
|
|
||||||
Archive: '' as Resource<(card: Card, client: Client, e?: Event) => void>,
|
|
||||||
SendToBoard: '' as Resource<(card: Card, client: Client, e?: Event) => void>,
|
|
||||||
Delete: '' as Resource<(card: Card, client: Client, e?: Event) => void>
|
|
||||||
},
|
|
||||||
cardActionSupportedHandler: {
|
|
||||||
Join: '' as Resource<(card: Card, client: Client) => boolean>,
|
|
||||||
Archive: '' as Resource<(card: Card, client: Client) => boolean>,
|
|
||||||
SendToBoard: '' as Resource<(card: Card, client: Client) => boolean>,
|
|
||||||
Delete: '' as Resource<(card: Card, client: Client) => boolean>
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -16,7 +16,8 @@
|
|||||||
|
|
||||||
import type { Doc, WithLookup } from '@anticrm/core'
|
import type { Doc, WithLookup } from '@anticrm/core'
|
||||||
import core, { Class, Client, matchQuery, Ref } from '@anticrm/core'
|
import core, { Class, Client, matchQuery, Ref } from '@anticrm/core'
|
||||||
import type { Action, ViewActionInput, ViewContextType } from '@anticrm/view'
|
import { getResource } from '@anticrm/platform'
|
||||||
|
import type { Action, ViewAction, ViewActionInput, ViewContextType } from '@anticrm/view'
|
||||||
import view from './plugin'
|
import view from './plugin'
|
||||||
import { FocusSelection } from './selection'
|
import { FocusSelection } from './selection'
|
||||||
|
|
||||||
@ -80,6 +81,16 @@ export async function getActions (
|
|||||||
return filteredActions
|
return filteredActions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function invokeAction (
|
||||||
|
object: Doc | Doc[],
|
||||||
|
evt: Event,
|
||||||
|
action: ViewAction,
|
||||||
|
props?: Record<string, any>
|
||||||
|
): Promise<void> {
|
||||||
|
const impl = await getResource(action)
|
||||||
|
await impl(Array.isArray(object) && object.length === 1 ? object[0] : object, evt, props)
|
||||||
|
}
|
||||||
|
|
||||||
export async function getContextActions (
|
export async function getContextActions (
|
||||||
client: Client,
|
client: Client,
|
||||||
doc: Doc | Doc[],
|
doc: Doc | Doc[],
|
||||||
|
@ -15,11 +15,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Class, Doc, Ref } from '@anticrm/core'
|
import type { Class, Doc, Ref } from '@anticrm/core'
|
||||||
import type { Asset } from '@anticrm/platform'
|
import type { Asset } from '@anticrm/platform'
|
||||||
import { getResource } from '@anticrm/platform'
|
|
||||||
import { getClient } from '@anticrm/presentation'
|
import { getClient } from '@anticrm/presentation'
|
||||||
import { Action, Menu } from '@anticrm/ui'
|
import { Action, Menu } from '@anticrm/ui'
|
||||||
import { ViewAction } from '@anticrm/view'
|
import { getActions, invokeAction } from '../actions'
|
||||||
import { getActions } from '../actions'
|
|
||||||
|
|
||||||
export let object: Doc | Doc[]
|
export let object: Doc | Doc[]
|
||||||
export let baseMenuClass: Ref<Class<Doc>> | undefined = undefined
|
export let baseMenuClass: Ref<Class<Doc>> | undefined = undefined
|
||||||
@ -27,10 +25,6 @@
|
|||||||
|
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
|
|
||||||
async function invokeAction (evt: Event, action: ViewAction, props?: Record<string, any>) {
|
|
||||||
const impl = await getResource(action)
|
|
||||||
await impl(Array.isArray(object) && object.length === 1 ? object[0] : object, evt, props)
|
|
||||||
}
|
|
||||||
let loaded = 0
|
let loaded = 0
|
||||||
|
|
||||||
getActions(client, object, baseMenuClass).then((result) => {
|
getActions(client, object, baseMenuClass).then((result) => {
|
||||||
@ -38,7 +32,7 @@
|
|||||||
label: a.label,
|
label: a.label,
|
||||||
icon: a.icon as Asset,
|
icon: a.icon as Asset,
|
||||||
action: async (_: any, evt: Event) => {
|
action: async (_: any, evt: Event) => {
|
||||||
invokeAction(evt, a.action, a.actionProps)
|
invokeAction(object, evt, a.action, a.actionProps)
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
loaded = 1
|
loaded = 1
|
||||||
|
@ -47,7 +47,7 @@ import DocAttributeBar from './components/DocAttributeBar.svelte'
|
|||||||
import ViewletSetting from './components/ViewletSetting.svelte'
|
import ViewletSetting from './components/ViewletSetting.svelte'
|
||||||
import TableBrowser from './components/TableBrowser.svelte'
|
import TableBrowser from './components/TableBrowser.svelte'
|
||||||
|
|
||||||
export { getActions } from './actions'
|
export { getActions, invokeAction } from './actions'
|
||||||
export { default as ActionContext } from './components/ActionContext.svelte'
|
export { default as ActionContext } from './components/ActionContext.svelte'
|
||||||
export { default as ActionHandler } from './components/ActionHandler.svelte'
|
export { default as ActionHandler } from './components/ActionHandler.svelte'
|
||||||
export { default as ContextMenu } from './components/Menu.svelte'
|
export { default as ContextMenu } from './components/Menu.svelte'
|
||||||
|
Loading…
Reference in New Issue
Block a user