From 7b49752288a900f824f29e67eba57d664c6a1388 Mon Sep 17 00:00:00 2001 From: Alex <41288429+Dvinyanin@users.noreply.github.com> Date: Tue, 17 May 2022 14:12:33 +0700 Subject: [PATCH] Board: Add TableView (#1760) Signed-off-by: Dvinyanin Alexandr <dvinyanin.alexandr@gmail.com> --- models/board/src/index.ts | 17 ++++++++++ models/board/src/plugin.ts | 6 ++-- .../src/components/BoardHeader.svelte | 31 +++++++++++++++-- .../src/components/TableView.svelte | 33 +++++++++++++++++++ .../src/components/UserBoxList.svelte | 11 +++++++ plugins/board-resources/src/index.ts | 8 ++++- plugins/board-resources/src/plugin.ts | 4 ++- .../src/components/SpaceView.svelte | 9 ++++- 8 files changed, 111 insertions(+), 8 deletions(-) create mode 100644 plugins/board-resources/src/components/TableView.svelte create mode 100644 plugins/board-resources/src/components/UserBoxList.svelte diff --git a/models/board/src/index.ts b/models/board/src/index.ts index f326ac984f..8b37f52b43 100644 --- a/models/board/src/index.ts +++ b/models/board/src/index.ts @@ -214,6 +214,12 @@ export function createModel (builder: Builder): void { config: [] }) + builder.createDoc(view.class.Viewlet, core.space.Model, { + attachTo: board.class.Card, + descriptor: board.viewlet.Table, + config: [] + }) + builder.mixin(board.class.Card, core.class.Class, task.mixin.KanbanCard, { card: board.component.KanbanCard }) @@ -260,6 +266,17 @@ export function createModel (builder: Builder): void { board.viewlet.Kanban ) + builder.createDoc( + view.class.ViewletDescriptor, + core.space.Model, + { + label: view.string.Table, + icon: view.icon.Table, + component: board.component.TableView + }, + board.viewlet.Table + ) + // card actions builder.createDoc( board.class.CardAction, diff --git a/models/board/src/plugin.ts b/models/board/src/plugin.ts index 3c1ffc807f..022d9b7d26 100644 --- a/models/board/src/plugin.ts +++ b/models/board/src/plugin.ts @@ -33,7 +33,8 @@ export default mergeIds(boardId, board, { BoardPresenter: '' as AnyComponent, TemplatesIcon: '' as AnyComponent, Cards: '' as AnyComponent, - KanbanView: '' as AnyComponent + KanbanView: '' as AnyComponent, + TableView: '' as AnyComponent }, space: { DefaultBoard: '' as Ref<Space> @@ -45,7 +46,8 @@ export default mergeIds(boardId, board, { Sequence: '' as Ref<Sequence> }, viewlet: { - Kanban: '' as Ref<ViewletDescriptor> + Kanban: '' as Ref<ViewletDescriptor>, + Table: '' as Ref<ViewletDescriptor> }, string: { LabelsCompactMode: '' as IntlString diff --git a/plugins/board-resources/src/components/BoardHeader.svelte b/plugins/board-resources/src/components/BoardHeader.svelte index 6d0f4bba15..ebaeeb7c47 100644 --- a/plugins/board-resources/src/components/BoardHeader.svelte +++ b/plugins/board-resources/src/components/BoardHeader.svelte @@ -1,11 +1,17 @@ <script lang="ts"> - import core, { Ref, Space } from '@anticrm/core' - import { Button, getCurrentLocation, navigate, location } from '@anticrm/ui' + import core, { Ref, Space, WithLookup } from '@anticrm/core' + import { Button, getCurrentLocation, navigate, location, Tooltip, Icon } from '@anticrm/ui' import { createQuery, getClient } from '@anticrm/presentation' import { Header, classIcon } from '@anticrm/chunter-resources' import border from '../plugin' + import { Viewlet } from '@anticrm/view' + import { createEventDispatcher } from 'svelte' export let spaceId: Ref<Space> | undefined + export let viewlets: WithLookup<Viewlet>[] + export let viewlet: WithLookup<Viewlet> + + const dispatch = createEventDispatcher() let space: Space const query = createQuery() @@ -20,12 +26,31 @@ loc.path[3] = space._id navigate(loc) } - $: showMenuButton = $location.path[3] !== spaceId + $: showMenuButton = $location.path[3] === undefined </script> <div class="ac-header divide full"> {#if space} <Header icon={classIcon(client, space._class)} label={space.name} description={space.description} /> + {#if viewlets.length > 1} + <div class="flex"> + {#each viewlets as v, i} + <Tooltip label={v.$lookup?.descriptor?.label} direction={'top'}> + <button + class="ac-header__icon-button" + class:selected={viewlet?._id === v._id} + on:click={() => { + dispatch('change', v) + }} + > + {#if v.$lookup?.descriptor?.icon} + <Icon icon={v.$lookup?.descriptor?.icon} size={'small'} /> + {/if} + </button> + </Tooltip> + {/each} + </div> + {/if} {#if showMenuButton} <Button label={border.string.ShowMenu} on:click={showMenu} /> {/if} diff --git a/plugins/board-resources/src/components/TableView.svelte b/plugins/board-resources/src/components/TableView.svelte new file mode 100644 index 0000000000..045101c609 --- /dev/null +++ b/plugins/board-resources/src/components/TableView.svelte @@ -0,0 +1,33 @@ +<script lang="ts"> + import { Card } from '@anticrm/board' + import { Class, FindOptions, Ref } from '@anticrm/core' + import { createQuery } from '@anticrm/presentation' + import task, { SpaceWithStates, State } from '@anticrm/task' + import { TableBrowser } from '@anticrm/view-resources' + import board from '../plugin' + + export let _class: Ref<Class<Card>> + export let space: Ref<SpaceWithStates> + export let options: FindOptions<Card> | undefined + + const isArchived = { $nin: [true] } + const query = createQuery() + let states: Ref<State>[] + $: query.query(task.class.State, { space, isArchived }, (result) => { + states = result.map(({ _id }) => _id) + }) +</script> + +<TableBrowser + {_class} + config={[ + 'title', + '$lookup.state', + { key: '', presenter: board.component.CardLabels, label: board.string.Labels }, + 'date', + { key: 'members', presenter: board.component.UserBoxList, label: board.string.Members, sortingKey: '' }, + 'modifiedOn' + ]} + {options} + query={{ isArchived, state: { $in: states } }} +/> diff --git a/plugins/board-resources/src/components/UserBoxList.svelte b/plugins/board-resources/src/components/UserBoxList.svelte new file mode 100644 index 0000000000..ba11bccd81 --- /dev/null +++ b/plugins/board-resources/src/components/UserBoxList.svelte @@ -0,0 +1,11 @@ +<script lang="ts"> + import contact, { Employee } from '@anticrm/contact' + import { Ref } from '@anticrm/core' + + import { UserBoxList } from '@anticrm/presentation' + import board from '../plugin' + + export let value: Ref<Employee>[] +</script> + +<UserBoxList items={value} _class={contact.class.Employee} label={board.string.Members} /> diff --git a/plugins/board-resources/src/index.ts b/plugins/board-resources/src/index.ts index 949e5edeb7..d90e40114c 100644 --- a/plugins/board-resources/src/index.ts +++ b/plugins/board-resources/src/index.ts @@ -41,6 +41,9 @@ import BoardHeader from './components/BoardHeader.svelte' import BoardMenu from './components/BoardMenu.svelte' import MenuMainPage from './components/MenuMainPage.svelte' import Archive from './components/Archive.svelte' +import TableView from './components/TableView.svelte' +import UserBoxList from './components/UserBoxList.svelte' +import CardLabels from './components/editor/CardLabels.svelte' import board from './plugin' import { addCurrentUser, @@ -119,7 +122,10 @@ export default async (): Promise<Resources> => ({ BoardHeader, BoardMenu, Archive, - MenuMainPage + MenuMainPage, + TableView, + UserBoxList, + CardLabels }, cardActionHandler: { Join: addCurrentUser, diff --git a/plugins/board-resources/src/plugin.ts b/plugins/board-resources/src/plugin.ts index 3acc93433b..1dbbdb3b87 100644 --- a/plugins/board-resources/src/plugin.ts +++ b/plugins/board-resources/src/plugin.ts @@ -134,6 +134,8 @@ export default mergeIds(boardId, board, { BoardHeader: '' as AnyComponent, BoardMenu: '' as AnyComponent, Archive: '' as AnyComponent, - MenuMainPage: '' as AnyComponent + MenuMainPage: '' as AnyComponent, + UserBoxList: '' as AnyComponent, + CardLabels: '' as AnyComponent } }) diff --git a/plugins/workbench-resources/src/components/SpaceView.svelte b/plugins/workbench-resources/src/components/SpaceView.svelte index 4f3474f497..82de884739 100644 --- a/plugins/workbench-resources/src/components/SpaceView.svelte +++ b/plugins/workbench-resources/src/components/SpaceView.svelte @@ -74,11 +74,18 @@ if (headerMixin?.header == null && clazz.extends != null) return getHeader(clazz.extends) return headerMixin.header } + function setViewlet (e: CustomEvent<WithLookup<Viewlet>>) { + viewlet = e.detail + } </script> {#if _class && space} {#if header} - <Component is={header} props={{ spaceId: space._id, viewlets, createItemDialog, createItemLabel }} /> + <Component + is={header} + props={{ spaceId: space._id, viewlets, viewlet, createItemDialog, createItemLabel }} + on:change={setViewlet} + /> {:else} <SpaceHeader spaceId={space._id} {viewlets} {createItemDialog} {createItemLabel} bind:search bind:viewlet /> {/if}