mirror of
https://github.com/hcengineering/platform.git
synced 2024-11-22 11:42:30 +03:00
Board: Design card editor (initial) (#1292)
This commit is contained in:
parent
167a5c3206
commit
6543fdf4b7
@ -25,7 +25,6 @@ export default mergeIds(boardId, board, {
|
||||
component: {
|
||||
CreateBoard: '' as AnyComponent,
|
||||
CreateCard: '' as AnyComponent,
|
||||
EditCard: '' as AnyComponent,
|
||||
KanbanCard: '' as AnyComponent,
|
||||
CardPresenter: '' as AnyComponent,
|
||||
TemplatesIcon: '' as AnyComponent,
|
||||
|
@ -172,6 +172,9 @@ p:last-child { margin-block-end: 0; }
|
||||
.justify-end { justify-content: flex-end; }
|
||||
.items-baseline { align-items: baseline; }
|
||||
|
||||
.flex-gap-3 {gap: .75rem;}
|
||||
.flex-gap-1 {gap: .25rem;}
|
||||
|
||||
.flex-presenter, .inline-presenter {
|
||||
flex-wrap: nowrap;
|
||||
cursor: pointer;
|
||||
@ -313,6 +316,9 @@ p:last-child { margin-block-end: 0; }
|
||||
.pr-4 { padding-right: 1rem; }
|
||||
.pr-24 { padding-right: 6rem; }
|
||||
|
||||
.p-2 { padding: .5rem; }
|
||||
.p-3 { padding: .75rem; }
|
||||
.p-6 { padding: 1.5rem; }
|
||||
.p-10 { padding: 2.5rem; }
|
||||
|
||||
/* --------- */
|
||||
@ -356,6 +362,7 @@ p:last-child { margin-block-end: 0; }
|
||||
.h-2 { height: .5rem; }
|
||||
.h-9 { height: 2.25rem; }
|
||||
.w-full { width: 100%; }
|
||||
.w-9 { width: 2.25rem; }
|
||||
.w-85 {width: 21.25rem; }
|
||||
.w-165 {width: 41.25rem; }
|
||||
.min-w-0 { min-width: 0; }
|
||||
@ -416,11 +423,7 @@ a.no-line {
|
||||
.pointer-events-none { pointer-events: none; }
|
||||
|
||||
/* Text */
|
||||
.text-sm { font-size: .75rem; }
|
||||
.text-md { font-size: .8125rem; }
|
||||
.text-lg { font-size: 1.125rem; }
|
||||
.font-normal { font-weight: 400; }
|
||||
.font-medium { font-weight: 500; }
|
||||
|
||||
.fs-title {
|
||||
font-weight: 500;
|
||||
font-size: 1rem;
|
||||
@ -434,6 +437,11 @@ a.no-line {
|
||||
color: var(--theme-content-trans-color);
|
||||
user-select: none;
|
||||
}
|
||||
.text-sm { font-size: .75rem; }
|
||||
.text-md { font-size: .8125rem; }
|
||||
.text-lg { font-size: 1.125rem; }
|
||||
.font-normal { font-weight: 400; }
|
||||
.font-medium { font-weight: 500; }
|
||||
.fs-bold { font-weight: 500; }
|
||||
.uppercase { text-transform: uppercase; }
|
||||
.text-left { text-align: left; }
|
||||
@ -529,6 +537,8 @@ a.no-line {
|
||||
|
||||
.red-color { color: var(--highlight-red); }
|
||||
|
||||
.border-radius-3 {border-radius: 0.75rem;}
|
||||
.border-bg-accent {border: 1px solid var(--theme-bg-accent-color);}
|
||||
.border-primary-button { border-color: var(--primary-button-border); }
|
||||
.border-button-enabled { border: 1px solid var(--theme-button-border-enabled); }
|
||||
.bottom-divider { border-bottom: 1px solid var(--theme-menu-divider); }
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
export let object: Doc
|
||||
export let fullSize: boolean = false
|
||||
export let showCommenInput: boolean = true
|
||||
export let transparent: boolean = false
|
||||
|
||||
let txes: DisplayTx[] = []
|
||||
@ -39,7 +40,7 @@
|
||||
const descriptors = createQuery()
|
||||
$: descriptors.query(activity.class.TxViewlet, {}, (result) => {
|
||||
viewlets = new Map(result.map((r) => [activityKey(r.objectClass, r.txClass), r]))
|
||||
|
||||
|
||||
editable = new Map(result.map(it => [it.objectClass, it.editable ?? false]))
|
||||
})
|
||||
|
||||
@ -78,9 +79,11 @@
|
||||
{/if}
|
||||
</div>
|
||||
</Scroller>
|
||||
<div class="ref-input">
|
||||
<Component is={chunter.component.CommentInput} props={{ object }} />
|
||||
</div>
|
||||
{#if showCommenInput}
|
||||
<div class="ref-input">
|
||||
<Component is={chunter.component.CommentInput} props={{ object }} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<Scroller>
|
||||
@ -105,9 +108,11 @@
|
||||
</div>
|
||||
</div>
|
||||
</Scroller>
|
||||
<div class="ref-input fill">
|
||||
<Component is={chunter.component.CommentInput} props={{ object }} />
|
||||
</div>
|
||||
{#if showCommenInput}
|
||||
<div class="ref-input fill">
|
||||
<Component is={chunter.component.CommentInput} props={{ object }} />
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
|
@ -20,9 +20,27 @@
|
||||
"Card": "Card",
|
||||
"Assignee": "Assignee",
|
||||
"Description": "Description",
|
||||
"DescriptionPlaceholder": "Add a more detailed description...",
|
||||
"Location": "Location",
|
||||
"Members": "Members",
|
||||
"BoardCreateLabel": "Board",
|
||||
"Settings": "Settings"
|
||||
"Settings": "Settings",
|
||||
"InList": "in list",
|
||||
"AddToCard": "Add to card",
|
||||
"Labels": "Labels",
|
||||
"Checklist": "Checklist",
|
||||
"Dates": "Dates",
|
||||
"Attachments": "Attachments",
|
||||
"CustomFields": "Custom Fields",
|
||||
"Automation": "Automation",
|
||||
"AddButton": "Add Button",
|
||||
"Actions": "Actions",
|
||||
"Move": "Move",
|
||||
"Copy": "Copy",
|
||||
"MakeTemplate": "Make Template",
|
||||
"Watch": "Watch",
|
||||
"Archive": "Archive",
|
||||
"HideDetails": "Hide Details",
|
||||
"ShowDetails": "Show Details"
|
||||
}
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
{
|
||||
"string": {
|
||||
"CreateBoard": "Create board",
|
||||
"CreateCard": "Create card",
|
||||
"CardName": "Card name",
|
||||
"CreateBoard": "Создать",
|
||||
"CreateCard": "Создать",
|
||||
"CardName": "Название",
|
||||
"Cards": "Cards",
|
||||
"SelectBoard": "Select board",
|
||||
"More": "More...",
|
||||
"SelectBoard": "Выбрать",
|
||||
"More": "Еще...",
|
||||
"Title": "Title",
|
||||
"ManageBoardStatuses": "Manage board statuses",
|
||||
"BoardName": "Board",
|
||||
@ -19,10 +19,28 @@
|
||||
"BoardApplication": "Boards",
|
||||
"Card": "Card",
|
||||
"Assignee": "Assignee",
|
||||
"Description": "Description",
|
||||
"Description": "Описание",
|
||||
"DescriptionPlaceholder": "Добавьте более подробное описание...",
|
||||
"Location": "Location",
|
||||
"Members": "Members",
|
||||
"Members": "Участники",
|
||||
"BoardCreateLabel": "Board",
|
||||
"Settings": "Settings"
|
||||
"Settings": "Настройки",
|
||||
"InList": "в списке",
|
||||
"AddToCard": "Добавить",
|
||||
"Labels": "Метки",
|
||||
"Checklist": "Списки",
|
||||
"Dates": "Дата",
|
||||
"Attachments": "Прикрепленное",
|
||||
"CustomFields": "Дополнительно",
|
||||
"Automation": "Автоматизация",
|
||||
"AddButton": "Добавить",
|
||||
"Actions": "Действия",
|
||||
"Move": "Переместить",
|
||||
"Copy": "Копировать",
|
||||
"MakeTemplate": "Шаблон",
|
||||
"Watch": "Отслеживать",
|
||||
"Archive": "Архивировать",
|
||||
"HideDetails": "Спрятать",
|
||||
"ShowDetails": "Показать"
|
||||
}
|
||||
}
|
@ -12,39 +12,42 @@
|
||||
"format": "prettier --write --plugin-search-dir=. src && eslint --fix src"
|
||||
},
|
||||
"devDependencies": {
|
||||
"svelte-loader": "^3.1.2",
|
||||
"sass": "^1.37.5",
|
||||
"svelte-preprocess": "^4.10.5",
|
||||
"@anticrm/platform-rig": "~0.6.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
||||
"@typescript-eslint/parser": "^5.4.0",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-standard-with-typescript": "^21.0.1",
|
||||
"eslint-plugin-import": "^2.25.3",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^5.1.1",
|
||||
"eslint-plugin-svelte3": "~3.2.1",
|
||||
"prettier-plugin-svelte": "^2.2.0",
|
||||
"eslint": "^7.32.0",
|
||||
"prettier": "^2.4.1",
|
||||
"prettier-plugin-svelte": "^2.2.0",
|
||||
"sass": "^1.37.5",
|
||||
"svelte-check": "^2.2.10",
|
||||
"svelte-loader": "^3.1.2",
|
||||
"svelte-preprocess": "^4.10.5",
|
||||
"typescript": "^4.3.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@anticrm/platform": "~0.6.5",
|
||||
"svelte": "^3.46",
|
||||
"@anticrm/board": "~0.6.0",
|
||||
"@anticrm/ui": "~0.6.0",
|
||||
"@anticrm/presentation": "~0.6.2",
|
||||
"@anticrm/core": "~0.6.16",
|
||||
"@anticrm/panel": "~0.6.0",
|
||||
"@anticrm/contact": "~0.6.5",
|
||||
"@anticrm/view": "~0.6.0",
|
||||
"@anticrm/task": "~0.6.0",
|
||||
"@anticrm/workbench": "~0.6.1",
|
||||
"@anticrm/view-resources": "~0.6.0",
|
||||
"@anticrm/activity": "~0.6.0",
|
||||
"@anticrm/attachment-resources": "~0.6.0",
|
||||
"@anticrm/contact-resources": "~0.6.0",
|
||||
"@anticrm/board": "~0.6.0",
|
||||
"@anticrm/chunter": "~0.6.1",
|
||||
"@anticrm/chunter-resources": "~0.6.0",
|
||||
"@anticrm/notification": "~0.6.0"
|
||||
"@anticrm/contact": "~0.6.5",
|
||||
"@anticrm/contact-resources": "~0.6.0",
|
||||
"@anticrm/core": "~0.6.16",
|
||||
"@anticrm/notification": "~0.6.0",
|
||||
"@anticrm/panel": "~0.6.0",
|
||||
"@anticrm/platform": "~0.6.5",
|
||||
"@anticrm/presentation": "~0.6.2",
|
||||
"@anticrm/task": "~0.6.0",
|
||||
"@anticrm/text-editor": "~0.6.0",
|
||||
"@anticrm/ui": "~0.6.0",
|
||||
"@anticrm/view": "~0.6.0",
|
||||
"@anticrm/view-resources": "~0.6.0",
|
||||
"@anticrm/workbench": "~0.6.1",
|
||||
"svelte": "^3.46"
|
||||
}
|
||||
}
|
||||
|
@ -17,13 +17,13 @@
|
||||
import type { Card } from '@anticrm/board'
|
||||
import { Icon, showPanel } from '@anticrm/ui'
|
||||
import view from '@anticrm/view'
|
||||
import lead from '../plugin'
|
||||
import board from '../plugin'
|
||||
|
||||
export let value: Card
|
||||
export let inline: boolean = false
|
||||
|
||||
async function show () {
|
||||
showPanel(view.component.EditDoc, value._id, value._class, 'middle')
|
||||
showPanel(board.component.EditCard, value._id, value._class, 'middle')
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -35,7 +35,7 @@
|
||||
on:click={show}
|
||||
>
|
||||
<div class="icon">
|
||||
<Icon icon={lead.icon.Board} size={'small'} />
|
||||
<Icon icon={board.icon.Card} size={'small'} />
|
||||
</div>
|
||||
<span class="label">{value.title}</span>
|
||||
</a>
|
||||
|
@ -33,22 +33,21 @@
|
||||
|
||||
const client = getClient()
|
||||
|
||||
async function createFunnel (): Promise<void> {
|
||||
if (templateId !== undefined && await client.findOne(task.class.KanbanTemplate, { _id: templateId }) === undefined) {
|
||||
async function createBoard (): Promise<void> {
|
||||
if (
|
||||
templateId !== undefined &&
|
||||
(await client.findOne(task.class.KanbanTemplate, { _id: templateId })) === undefined
|
||||
) {
|
||||
throw Error(`Failed to find target kanban template: ${templateId}`)
|
||||
}
|
||||
|
||||
const id = await client.createDoc(
|
||||
board.class.Board,
|
||||
core.space.Space,
|
||||
{
|
||||
name,
|
||||
description,
|
||||
private: false,
|
||||
archived: false,
|
||||
members: []
|
||||
}
|
||||
)
|
||||
const id = await client.createDoc(board.class.Board, core.space.Space, {
|
||||
name,
|
||||
description,
|
||||
private: false,
|
||||
archived: false,
|
||||
members: []
|
||||
})
|
||||
|
||||
await createKanban(client, id, templateId)
|
||||
}
|
||||
@ -56,22 +55,32 @@
|
||||
|
||||
<SpaceCreateCard
|
||||
label={board.string.CreateBoard}
|
||||
okAction={createFunnel}
|
||||
okAction={createBoard}
|
||||
canSave={name.length > 0}
|
||||
on:close={() => {
|
||||
dispatch('close')
|
||||
}}
|
||||
>
|
||||
<Grid column={1} rowGap={1.5}>
|
||||
<EditBox label={board.string.BoardName} icon={IconFolder} bind:value={name} placeholder={board.string.Board} maxWidth={'16rem'} focus />
|
||||
<EditBox
|
||||
label={board.string.BoardName}
|
||||
icon={IconFolder}
|
||||
bind:value={name}
|
||||
placeholder={board.string.Board}
|
||||
maxWidth={'16rem'}
|
||||
focus
|
||||
/>
|
||||
<!-- <ToggleWithLabel label={board.string.MakePrivate} description={board.string.MakePrivateDescription} /> -->
|
||||
|
||||
<Component is={task.component.KanbanTemplateSelector} props={{
|
||||
folders: [board.space.BoardTemplates],
|
||||
template: templateId
|
||||
}} on:change={(evt) => {
|
||||
templateId = evt.detail
|
||||
}}/>
|
||||
|
||||
<Component
|
||||
is={task.component.KanbanTemplateSelector}
|
||||
props={{
|
||||
folders: [board.space.BoardTemplates],
|
||||
template: templateId
|
||||
}}
|
||||
on:change={(evt) => {
|
||||
templateId = evt.detail
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
</SpaceCreateCard>
|
||||
|
@ -15,18 +15,42 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import type { Card } from '@anticrm/board'
|
||||
import { getClient } from '@anticrm/presentation'
|
||||
import { EditBox, Grid } from '@anticrm/ui'
|
||||
import { Class, Ref } from '@anticrm/core'
|
||||
import { createQuery, getClient } from '@anticrm/presentation'
|
||||
import type { State } from '@anticrm/task'
|
||||
import task from '@anticrm/task'
|
||||
import { StyledTextBox } from '@anticrm/text-editor'
|
||||
import { Button, EditBox, Icon, IconClose, Label, Scroller } from '@anticrm/ui'
|
||||
import { createEventDispatcher, onMount } from 'svelte'
|
||||
import board from '../plugin'
|
||||
import CardActions from './editor/CardActions.svelte'
|
||||
import CardActivity from './editor/CardActivity.svelte'
|
||||
import CardFields from './editor/CardFields.svelte'
|
||||
|
||||
export let object: Card
|
||||
|
||||
export let _id: Ref<Card>
|
||||
export let _class: Ref<Class<Card>>
|
||||
const dispatch = createEventDispatcher()
|
||||
const client = getClient()
|
||||
const query = createQuery()
|
||||
|
||||
let object: Card | undefined
|
||||
let state: State | undefined
|
||||
|
||||
$: _id &&
|
||||
_class &&
|
||||
query.query(_class, { _id }, async (result) => {
|
||||
object = result[0]
|
||||
})
|
||||
|
||||
$: object &&
|
||||
query.query(task.class.State, { _id: object.state }, async (result) => {
|
||||
state = result[0]
|
||||
})
|
||||
|
||||
function change (field: string, value: any) {
|
||||
client.updateDoc(object._class, object.space, object._id, { [field]: value })
|
||||
if (object) {
|
||||
client.update(object, { [field]: value })
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
@ -35,15 +59,74 @@
|
||||
</script>
|
||||
|
||||
{#if object !== undefined}
|
||||
<Grid column={1} rowGap={1.5}>
|
||||
<EditBox
|
||||
label={board.string.CardName}
|
||||
bind:value={object.title}
|
||||
icon={board.icon.Card}
|
||||
placeholder={board.string.CardPlaceholder}
|
||||
maxWidth="39rem"
|
||||
focus
|
||||
on:change={() => change('title', object.title)}
|
||||
/>
|
||||
</Grid>
|
||||
<Scroller>
|
||||
<div class="flex-col-stretch h-full w-165 p-6">
|
||||
<!-- TODO cover -->
|
||||
<div class="close-button">
|
||||
<Button icon={IconClose} kind="transparent" size="large" on:click={() => dispatch('close')} />
|
||||
</div>
|
||||
<div class="flex-row-streach">
|
||||
<div class="w-9">
|
||||
<Icon icon={board.icon.Card} size="large" />
|
||||
</div>
|
||||
<div class="fs-title text-lg">
|
||||
<EditBox bind:value={object.title} maxWidth="39rem" focus on:change={() => change('title', object?.title)} />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-row-streach">
|
||||
<div class="w-9" />
|
||||
<div>
|
||||
<Label label={board.string.InList} /><span class="state-name ml-1">{state?.title}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-row-streach">
|
||||
<div class="flex-grow mr-4">
|
||||
<div class="flex-row-streach">
|
||||
<div class="w-9" />
|
||||
<CardFields value={object} />
|
||||
</div>
|
||||
<div class="flex-row-streach mt-4 mb-2">
|
||||
<div class="w-9">
|
||||
<Icon icon={board.icon.Card} size="large" />
|
||||
</div>
|
||||
<div class="fs-title">
|
||||
<Label label={board.string.Description} />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-row-streach">
|
||||
<div class="w-9" />
|
||||
<div class="background-bg-accent border-bg-accent border-radius-3 p-2 w-full">
|
||||
<StyledTextBox
|
||||
alwaysEdit={true}
|
||||
showButtons={false}
|
||||
placeholder={board.string.DescriptionPlaceholder}
|
||||
bind:content={object.description}
|
||||
on:value={(evt) => change('description', evt.detail)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- TODO attachments-->
|
||||
<!-- TODO checklists -->
|
||||
<CardActivity value={object} />
|
||||
</div>
|
||||
|
||||
<CardActions value={object} />
|
||||
</div>
|
||||
</div>
|
||||
</Scroller>
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
.close-button {
|
||||
position: absolute;
|
||||
top: 0.7rem;
|
||||
right: 0.7rem;
|
||||
}
|
||||
.state-name {
|
||||
text-decoration: underline;
|
||||
|
||||
&:hover {
|
||||
color: var(--caption-color);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -20,7 +20,6 @@
|
||||
import type { WithLookup } from '@anticrm/core'
|
||||
import notification from '@anticrm/notification'
|
||||
import { ActionIcon, Component, IconMoreH, showPanel, showPopup } from '@anticrm/ui'
|
||||
import view from '@anticrm/view'
|
||||
import { ContextMenu } from '@anticrm/view-resources'
|
||||
import board from '../plugin'
|
||||
|
||||
@ -33,11 +32,11 @@
|
||||
}
|
||||
|
||||
function showLead () {
|
||||
showPanel(view.component.EditDoc, object._id, object._class, 'middle')
|
||||
showPanel(board.component.EditCard, object._id, object._class, 'middle')
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="card-container" {draggable} class:draggable on:dragstart on:dragend class:dragged={dragged}>
|
||||
<div class="card-container" {draggable} class:draggable on:dragstart on:dragend class:dragged>
|
||||
<div class="flex-between mb-4">
|
||||
<div class="flex-col">
|
||||
<div class="fs-title cursor-pointer" on:click={showLead}>{object.title}</div>
|
||||
@ -56,7 +55,7 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-between">
|
||||
<div class="flex-between">
|
||||
<div class="flex-row-center">
|
||||
{#if (object.attachments ?? 0) > 0}
|
||||
<div class="step-lr75"><AttachmentsPresenter value={object} /></div>
|
||||
@ -72,14 +71,14 @@
|
||||
.card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: .5rem 1rem;
|
||||
padding: 0.5rem 1rem;
|
||||
background-color: var(--board-card-bg-color);
|
||||
border: 1px solid var(--board-card-bg-color);
|
||||
border-radius: .25rem;
|
||||
border-radius: 0.25rem;
|
||||
user-select: none;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--board-card-bg-hover);
|
||||
&:hover {
|
||||
background-color: var(--board-card-bg-hover);
|
||||
}
|
||||
&.draggable {
|
||||
cursor: grab;
|
||||
|
@ -12,6 +12,6 @@
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
color: #fff;
|
||||
background-color: #4474F6;
|
||||
background-color: #4474f6;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
@ -0,0 +1,43 @@
|
||||
<!--
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2021 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 } from '@anticrm/board'
|
||||
import { Button, Label } from '@anticrm/ui'
|
||||
import { getEditorCardActionGroups } from '../../utils/CardActionUtils'
|
||||
|
||||
export let value: Card
|
||||
|
||||
const actionGroups = getEditorCardActionGroups(value)
|
||||
</script>
|
||||
|
||||
{#if value}
|
||||
<div class="flex-col flex-gap-3">
|
||||
{#each actionGroups as group}
|
||||
<div class="flex-col flex-gap-1">
|
||||
<Label label={group.label} />
|
||||
{#each group.actions as action}
|
||||
<Button
|
||||
icon={action.icon}
|
||||
label={action.label}
|
||||
kind={action.isTransparent ? 'transparent' : 'no-border'}
|
||||
justify="left"
|
||||
on:click={() => action.handler?.(value)}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
@ -0,0 +1,59 @@
|
||||
<!--
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2021 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 activity from '@anticrm/activity'
|
||||
import type { Card } from '@anticrm/board'
|
||||
import chunter from '@anticrm/chunter'
|
||||
import { Button, Component, Icon, IconActivity, Label } from '@anticrm/ui'
|
||||
import board from '../../plugin'
|
||||
|
||||
export let value: Card | undefined
|
||||
let isActivityShown: boolean = true
|
||||
</script>
|
||||
|
||||
{#if value !== undefined}
|
||||
<div class="flex-col-stretch h-full w-full">
|
||||
<!-- TODO attachments-->
|
||||
<!-- TODO checklists -->
|
||||
<div class="flex-row-streach mt-4 mb-2">
|
||||
<div class="w-9">
|
||||
<Icon icon={IconActivity} size="large" />
|
||||
</div>
|
||||
<div class="flex-grow fs-title">
|
||||
<Label label={activity.string.Activity} />
|
||||
</div>
|
||||
<Button
|
||||
kind="no-border"
|
||||
label={isActivityShown ? board.string.HideDetails : board.string.ShowDetails}
|
||||
width="100px"
|
||||
on:click={() => {
|
||||
isActivityShown = !isActivityShown
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div class="flex-row-streach">
|
||||
<div class="w-9" />
|
||||
<div class="w-full">
|
||||
<Component is={chunter.component.CommentInput} props={{ object: value }} />
|
||||
</div>
|
||||
</div>
|
||||
{#if isActivityShown === true}
|
||||
<Component is={activity.component.Activity} props={{ object: value, showCommenInput: false, transparent: true }}>
|
||||
<slot />
|
||||
</Component>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
@ -0,0 +1,24 @@
|
||||
<!--
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2021 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 } from '@anticrm/board'
|
||||
|
||||
export let value: Card
|
||||
</script>
|
||||
|
||||
{#if value}
|
||||
<div />
|
||||
{/if}
|
17
plugins/board-resources/src/models/CardAction.ts
Normal file
17
plugins/board-resources/src/models/CardAction.ts
Normal file
@ -0,0 +1,17 @@
|
||||
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
|
||||
}
|
@ -41,17 +41,35 @@ export default mergeIds(boardId, board, {
|
||||
Assignee: '' as IntlString,
|
||||
ManageBoardStatuses: '' as IntlString,
|
||||
Description: '' as IntlString,
|
||||
DescriptionPlaceholder: '' as IntlString,
|
||||
Location: '' as IntlString,
|
||||
Members: '' as IntlString,
|
||||
BoardCreateLabel: '' as IntlString,
|
||||
Settings: '' as IntlString
|
||||
Settings: '' as IntlString,
|
||||
InList: '' as IntlString,
|
||||
AddToCard: '' as IntlString,
|
||||
Labels: '' as IntlString,
|
||||
Checklist: '' as IntlString,
|
||||
Dates: '' as IntlString,
|
||||
Attachments: '' as IntlString,
|
||||
CustomFields: '' as IntlString,
|
||||
Automation: '' as IntlString,
|
||||
AddButton: '' as IntlString,
|
||||
Actions: '' as IntlString,
|
||||
Move: '' as IntlString,
|
||||
Copy: '' as IntlString,
|
||||
MakeTemplate: '' as IntlString,
|
||||
Watch: '' as IntlString,
|
||||
Archive: '' as IntlString,
|
||||
HideDetails: '' as IntlString,
|
||||
ShowDetails: '' as IntlString
|
||||
},
|
||||
component: {
|
||||
CreateCustomer: '' as AnyComponent,
|
||||
CardsPresenter: '' as AnyComponent,
|
||||
Boards: '' as AnyComponent,
|
||||
EditCard: '' as AnyComponent,
|
||||
Members: '' as AnyComponent,
|
||||
Settings: '' as AnyComponent
|
||||
|
||||
}
|
||||
})
|
||||
|
86
plugins/board-resources/src/utils/CardActionUtils.ts
Normal file
86
plugins/board-resources/src/utils/CardActionUtils.ts
Normal file
@ -0,0 +1,86 @@
|
||||
import { Card } from '@anticrm/board'
|
||||
import { IconAdd, IconAttachment } from '@anticrm/ui'
|
||||
import { CardAction, CardActionGroup } from '../models/CardAction'
|
||||
import board from '../plugin'
|
||||
|
||||
export const MembersAction: CardAction = {
|
||||
icon: board.icon.Card,
|
||||
label: board.string.Members
|
||||
}
|
||||
|
||||
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]
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue
Block a user