Delete action

Signed-off-by: Andrey Platov <andrey@hardcoreeng.com>
This commit is contained in:
Andrey Platov
2021-09-25 18:48:22 +02:00
parent 55ceee2372
commit 048bb9c71f
12 changed files with 1006 additions and 703 deletions
File diff suppressed because it is too large Load Diff
+297 -224
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -17,7 +17,7 @@ import { Builder } from '@anticrm/model'
import core from './component'
import { TAttribute, TClass, TDoc, TMixin, TObj, TType, TTypeString } from './core'
import { TSpace, TAccount, TState, TSpaceWithStates } from './security'
import { TTx, TTxCreateDoc, TTxMixin, TTxUpdateDoc, TTxCUD, TTxPutBag } from './tx'
import { TTx, TTxCreateDoc, TTxMixin, TTxUpdateDoc, TTxCUD, TTxPutBag, TTxRemoveDoc } from './tx'
export * from './core'
export * from './security'
@@ -36,6 +36,7 @@ export function createModel (builder: Builder): void {
TTxPutBag,
TTxMixin,
TTxUpdateDoc,
TTxRemoveDoc,
TSpace,
TSpaceWithStates,
TAccount,
+28 -4
View File
@@ -13,12 +13,12 @@
// limitations under the License.
//
import type { IntlString } from '@anticrm/platform'
import type { Ref, Class, Space } from '@anticrm/core'
import type { IntlString, Asset, Resource } from '@anticrm/platform'
import type { Ref, Class, Space, Doc } from '@anticrm/core'
import { DOMAIN_MODEL } from '@anticrm/core'
import { Model, Mixin, Builder } from '@anticrm/model'
import type { AnyComponent } from '@anticrm/ui'
import type { ViewletDescriptor, Viewlet, AttributeEditor, AttributePresenter, KanbanCard, ObjectEditor } from '@anticrm/view'
import type { ViewletDescriptor, Viewlet, AttributeEditor, AttributePresenter, KanbanCard, ObjectEditor, Action, ActionTarget } from '@anticrm/view'
import core, { TDoc, TClass } from '@anticrm/model-core'
@@ -57,8 +57,21 @@ export class TViewlet extends TDoc implements Viewlet {
config: any
}
@Model(view.class.Action, core.class.Doc, DOMAIN_MODEL)
export class TAction extends TDoc implements Action {
label!: IntlString
icon?: Asset
action!: Resource<(doc: Doc) => Promise<void>>
}
@Model(view.class.ActionTarget, core.class.Doc, DOMAIN_MODEL)
export class TActionTarget extends TDoc implements ActionTarget {
target!: Ref<Class<Doc>>
action!: Ref<Action>
}
export function createModel (builder: Builder): void {
builder.createModel(TAttributeEditor, TAttributePresenter, TKanbanCard, TObjectEditor, TViewletDescriptor, TViewlet)
builder.createModel(TAttributeEditor, TAttributePresenter, TKanbanCard, TObjectEditor, TViewletDescriptor, TViewlet, TAction, TActionTarget)
builder.mixin(core.class.TypeString, core.class.Class, view.mixin.AttributeEditor, {
editor: view.component.StringEditor
@@ -83,6 +96,17 @@ export function createModel (builder: Builder): void {
icon: view.icon.Kanban,
component: view.component.KanbanView
}, view.viewlet.Kanban)
builder.createDoc(view.class.Action, core.space.Model, {
label: 'Delete' as IntlString,
icon: view.icon.Kanban,
action: view.actionImpl.Delete
}, view.action.Delete)
builder.createDoc(view.class.ActionTarget, core.space.Model, {
target: core.class.Doc,
action: view.action.Delete
})
}
export default view
+9 -1
View File
@@ -14,10 +14,18 @@
//
import { mergeIds } from '@anticrm/platform'
import type { Ref, Doc } from '@anticrm/core'
import type { Resource } from '@anticrm/platform'
import type { AnyComponent } from '@anticrm/ui'
import view, { viewId } from '@anticrm/view'
import view, { viewId, Action } from '@anticrm/view'
export default mergeIds(viewId, view, {
action: {
Delete: '' as Ref<Action>
},
actionImpl: {
Delete: '' as Resource<(doc: Doc) => Promise<void>>
},
component: {
StringEditor: '' as AnyComponent,
StringPresenter: '' as AnyComponent,
@@ -14,34 +14,39 @@
-->
<script lang="ts">
import type { IntlString, Asset } from '@anticrm/platform'
import type { AnySvelteComponent } from '@anticrm/ui'
import type { IntlString, Asset, Resource } from '@anticrm/platform'
import { getResource } from '@anticrm/platform'
import { getClient, createQuery } from '@anticrm/presentation'
import type { Ref, Class, Doc } from '@anticrm/core'
import { createEventDispatcher } from 'svelte'
import { Icon, Label, IconMoreH, IconFile } from '@anticrm/ui'
import type { Action, ActionTarget } from '@anticrm/view'
import { getActions } from '../utils'
import view from '@anticrm/view'
export let title: IntlString
export let caption: IntlString
export let object: Doc
let actions: Action[] = []
interface PopupItem {
icon: Asset | AnySvelteComponent
label: IntlString
action?: () => Promise<void>
}
const client = getClient()
getActions(client, object._class).then(result => { actions = result })
const dispatch = createEventDispatcher()
const actions: Array<PopupItem> = [{ icon: IconFile, label: 'Application', action: async () => {} },
{ icon: IconMoreH, label: 'Options', action: async () => {} }]
async function invokeAction(action: Resource<(object: Doc) => Promise<void>>) {
dispatch('close')
const impl = await getResource(action)
await impl(object)
}
</script>
<div class="flex-col popup">
{#each actions as action}
<div class="flex-row-center menu-item" on:click={() => { dispatch('close') }}>
<div class="flex-row-center menu-item" on:click={() => { invokeAction(action.action) }}>
<div class="icon">
{#if typeof (action.icon) === 'string'}
<Icon icon={action.icon} size={'large'} />
{:else}
<svelte:component this={action.icon} size={'large'} />
{/if}
<Icon icon={action.icon} size={'large'} />
</div>
<div class="label"><Label label={action.label} /></div>
</div>
@@ -58,11 +58,12 @@
}
return false
}
const showMenu = (ev: MouseEvent): void => {
const showMenu = (ev: MouseEvent, object: Doc): void => {
const elRow: HTMLElement = findNode(ev.target as HTMLElement, 'tr-body')
const elBtn: HTMLElement = findNode(ev.target as HTMLElement, 'menuRow')
elRow.classList.add('fixed')
showPopup(Menu, {}, elBtn, (() => {
showPopup(Menu, { object }, elBtn, (() => {
elRow.classList.remove('fixed')
}))
}
@@ -100,7 +101,7 @@
<div class="firstCell">
<div class="control">
<CheckBox bind:checked={checking} />
<div class="menuRow" on:click={(ev) => showMenu(ev)}><MoreV size={'small'} /></div>
<div class="menuRow" on:click={(ev) => showMenu(ev, object)}><MoreV size={'small'} /></div>
</div>
<svelte:component this={attribute.presenter} value={getValue(object, attribute.key)}/>
</div>
+12
View File
@@ -13,13 +13,25 @@
// limitations under the License.
//
import type { Doc } from '@anticrm/core'
import StringEditor from './components/StringEditor.svelte'
import StringPresenter from './components/StringPresenter.svelte'
import StatePresenter from './components/StatePresenter.svelte'
import TableView from './components/TableView.svelte'
import KanbanView from './components/KanbanView.svelte'
import { getClient } from '@anticrm/presentation'
async function Delete(object: Doc): Promise<void> {
const client = getClient()
await client.removeDoc(object._class, object.space, object._id)
}
export default async () => ({
actionImpl: {
Delete
},
component: {
StringEditor,
StringPresenter,
+17 -1
View File
@@ -18,6 +18,7 @@ import type { IntlString } from '@anticrm/platform'
import { getResource } from '@anticrm/platform'
import type { Ref, Class, Obj, FindOptions, Doc, Client } from '@anticrm/core'
import type { AnyComponent, AnySvelteComponent } from '@anticrm/ui'
import type { Action, ActionTarget } from '@anticrm/view'
import view from '@anticrm/view'
@@ -98,4 +99,19 @@ export async function buildModel(client: Client, _class: Ref<Class<Obj>>, keys:
const model = keys.map(key => getPresenter(client, _class, key, key, options))
console.log(model)
return await Promise.all(model)
}
}
function filterActions(client: Client, _class: Ref<Class<Obj>>, targets: ActionTarget[]): Ref<Action>[] {
const result: Ref<Action>[] = []
for (const target of targets) {
if (client.getHierarchy().isDerived(_class, target.target)) {
result.push(target.action)
}
}
return result
}
export async function getActions(client: Client, _class: Ref<Class<Obj>>) {
const targets = await client.findAll(view.class.ActionTarget, {})
return await client.findAll(view.class.Action, { _id: { $in: filterActions(client, _class, targets) }})
}
+19 -2
View File
@@ -14,7 +14,7 @@
// limitations under the License.
//
import type { Plugin, Asset } from '@anticrm/platform'
import type { Plugin, Asset, Resource } from '@anticrm/platform'
import { plugin } from '@anticrm/platform'
import type { Ref, Mixin, UXObject, Space, FindOptions, Class, Doc } from '@anticrm/core'
@@ -66,6 +66,21 @@ export interface Viewlet extends Doc {
config: any
}
/**
* @public
*/
export interface Action extends Doc, UXObject {
action: Resource<(doc: Doc) => Promise<void>>
}
/**
* @public
*/
export interface ActionTarget extends Doc {
target: Ref<Class<Doc>>
action: Ref<Action>
}
/**
* @public
*/
@@ -80,7 +95,9 @@ export default plugin(viewId, {
},
class: {
ViewletDescriptor: '' as Ref<Class<ViewletDescriptor>>,
Viewlet: '' as Ref<Class<Viewlet>>
Viewlet: '' as Ref<Class<Viewlet>>,
Action: '' as Ref<Class<Action>>,
ActionTarget: '' as Ref<Class<ActionTarget>>
},
viewlet: {
Table: '' as Ref<ViewletDescriptor>,
+2 -2
View File
@@ -37,8 +37,8 @@ export class FullTextIndex extends TxProcessor implements Storage {
console.log('FullTextIndex.txPutBag: Method not implemented.')
}
protected txRemoveDoc (tx: TxRemoveDoc<Doc>): Promise<void> {
throw new Error('Method not implemented.')
protected override async txRemoveDoc (tx: TxRemoveDoc<Doc>): Promise<void> {
console.log('FullTextIndex.txRemoveDoc: Method not implemented.')
}
protected txMixin (tx: TxMixin<Doc, Doc>): Promise<void> {
File diff suppressed because it is too large Load Diff