mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-23 11:31:57 +03:00
Tasks MVP
1. Creation of projects 2. Creation of tasks 3. Task table display 4. Task Editing Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
parent
6b7a4b2474
commit
af096a0f66
@ -9864,7 +9864,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/dev-storage.tgz_typescript@4.4.3:
|
||||
resolution: {integrity: sha512-SfTtSgH07SlBF5nTXqS/E5023gdeN5eFmaL4fdrvId5ixenWnSJ16Xcvj02R8nuQ7PAwkNkZMwO+707Ins3GlQ==, tarball: file:projects/dev-storage.tgz}
|
||||
resolution: {integrity: sha512-MI95DMgzOe43SqSrvtR+wgcws3voLsrjvQAS87DGkq15UUxobrixatDGfk5rxFUJsGNpw68s0SQNB+XsYmB4Dw==, tarball: file:projects/dev-storage.tgz}
|
||||
id: file:projects/dev-storage.tgz
|
||||
name: '@rush-temp/dev-storage'
|
||||
version: 0.0.0
|
||||
@ -10267,7 +10267,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/model-task.tgz_typescript@4.4.3:
|
||||
resolution: {integrity: sha512-ECVFsBQDPeXBhwde4kBvnJlE8sXbSuSPOVa76QAdw4poccNaXabQbDUMNKNIquq4kTPGp7GhUUbaDk316zWmcw==, tarball: file:projects/model-task.tgz}
|
||||
resolution: {integrity: sha512-BFTI2YyRTQa+3voYij2r8icUkp5QdKc69N3oPvir4XsfrRrlM90EiDYi0XKk2YCjRtnn+2DEa+pjT8q4CQke5g==, tarball: file:projects/model-task.tgz}
|
||||
id: file:projects/model-task.tgz
|
||||
name: '@rush-temp/model-task'
|
||||
version: 0.0.0
|
||||
@ -10494,7 +10494,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/prod.tgz_sass@1.42.1+typescript@4.4.3:
|
||||
resolution: {integrity: sha512-jYkFXSc3TaFdljpFFcRvEWTmtHKLA7nQUn+9kSDD9/J91/LmQEv3yEyJH89kb1ETNiTK6vnuLlp9br+RZipWVg==, tarball: file:projects/prod.tgz}
|
||||
resolution: {integrity: sha512-YXR+9ndU1ibNRBgBG2s//HcelDIJmxvXqSPkrZ1A9z8qhjtnYGi7mwqIKpxS+mYVr5nS6JRCNLXcblAp7aDlXA==, tarball: file:projects/prod.tgz}
|
||||
id: file:projects/prod.tgz
|
||||
name: '@rush-temp/prod'
|
||||
version: 0.0.0
|
||||
@ -10868,13 +10868,24 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/task-resources.tgz_e1367da94684b005adf08f025c517b1a:
|
||||
resolution: {integrity: sha512-x8gVBObHY9bs86rKxU8Vq0uKMNgjvz5LFQqux6+l8aECuCJjjj70UcQqV+5hBGaY9m5GnlaxAJZed4VntxS4XA==, tarball: file:projects/task-resources.tgz}
|
||||
resolution: {integrity: sha512-dxx9fOd472gS8ILbnRMpBhnd4KOT0xkpQRbSkGHn9sigBeRZ48ZdEXtfagTQSaVlgwhOoCbVm1QrFy67Ctpbcw==, tarball: file:projects/task-resources.tgz}
|
||||
id: file:projects/task-resources.tgz
|
||||
name: '@rush-temp/task-resources'
|
||||
version: 0.0.0
|
||||
dependencies:
|
||||
'@typescript-eslint/eslint-plugin': 5.4.0_87dbf04088b125598d0271706532eaf3
|
||||
'@typescript-eslint/parser': 5.4.0_eslint@7.32.0+typescript@4.4.3
|
||||
eslint: 7.32.0
|
||||
eslint-config-standard-with-typescript: 21.0.1_05a8ea1454e6ca4c9f98b94b8f3abf9c
|
||||
eslint-plugin-import: 2.25.3_eslint@7.32.0
|
||||
eslint-plugin-node: 11.1.0_eslint@7.32.0
|
||||
eslint-plugin-promise: 5.1.1_eslint@7.32.0
|
||||
eslint-plugin-svelte3: 3.2.1_eslint@7.32.0+svelte@3.43.1
|
||||
prettier: 2.4.1
|
||||
prettier-plugin-svelte: 2.5.0_prettier@2.4.1+svelte@3.43.1
|
||||
sass: 1.42.1
|
||||
svelte: 3.43.1
|
||||
svelte-check: 2.2.10_3708ed3db7329f2cbf76db19160094b1
|
||||
svelte-loader: 3.1.2_svelte@3.43.1
|
||||
svelte-preprocess: 4.9.8_b1ccfb371c7d68f75291f5a547be0b14
|
||||
transitivePeerDependencies:
|
||||
@ -10887,6 +10898,7 @@ packages:
|
||||
- pug
|
||||
- stylus
|
||||
- sugarss
|
||||
- supports-color
|
||||
- typescript
|
||||
dev: false
|
||||
|
||||
@ -11009,7 +11021,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/tool.tgz_typescript@4.4.3:
|
||||
resolution: {integrity: sha512-4mquFHT6NpGnSQiTikfIdCakmJbxLsSCVn7f8X4j8DWwx+GKYLxi8O+NGHuB82dZ76XJoonako1CsiVGvrNpPA==, tarball: file:projects/tool.tgz}
|
||||
resolution: {integrity: sha512-SwaepBCYg7nNx+Vb5vkowQ2QYwf6KLw8iKJGWmm8A261c9geGd8f2Sl2DYyxi9lhG946DRaMxxnQkSfzvNZkRg==, tarball: file:projects/tool.tgz}
|
||||
id: file:projects/tool.tgz
|
||||
name: '@rush-temp/tool'
|
||||
version: 0.0.0
|
||||
@ -11189,7 +11201,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/workspace.tgz_typescript@4.4.3:
|
||||
resolution: {integrity: sha512-Mey3vBH1eqNXrxrhsXI3d66AoIW4hqE34OWI7KN7hqY0nqVzUcex0GHBc78dw7vS+UDkW1Cc2J6rCiLvYQkzfw==, tarball: file:projects/workspace.tgz}
|
||||
resolution: {integrity: sha512-RqzmT9xyUKDthUVU6kMT/yarSmB0yPv2q4VI6cJ+O/Iw7HiuKhTUV7ObyA6AJPIYiHZIGOqM4EMrMvX2G8rWNA==, tarball: file:projects/workspace.tgz}
|
||||
id: file:projects/workspace.tgz
|
||||
name: '@rush-temp/workspace'
|
||||
version: 0.0.0
|
||||
|
@ -20,7 +20,7 @@ import type { AnyComponent } from '@anticrm/ui'
|
||||
import type { Action } from '@anticrm/view'
|
||||
import { recruitId } from '@anticrm/recruit'
|
||||
import recruit from '@anticrm/recruit-resources/src/plugin'
|
||||
import { TxViewlet } from '../../chunter/node_modules/@anticrm/activity/lib'
|
||||
import { TxViewlet } from '@anticrm/activity'
|
||||
|
||||
export default mergeIds(recruitId, recruit, {
|
||||
action: {
|
||||
|
@ -28,6 +28,8 @@
|
||||
"@anticrm/model-workbench": "~0.6.1",
|
||||
"@anticrm/model-contact": "~0.6.1",
|
||||
"@anticrm/task": "~0.6.0",
|
||||
"@anticrm/task-resources": "~0.6.0"
|
||||
"@anticrm/task-resources": "~0.6.0",
|
||||
"@anticrm/model-chunter": "~0.6.0",
|
||||
"@anticrm/workbench": "~0.6.1"
|
||||
}
|
||||
}
|
||||
|
@ -13,34 +13,42 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import { Builder, Model, TypeString, UX, Prop } from '@anticrm/model'
|
||||
import type { Ref, Doc, FindOptions } from '@anticrm/core'
|
||||
import core, { TSpace, TDoc } from '@anticrm/model-core'
|
||||
import type { Project, Task } from '@anticrm/task'
|
||||
import type { Employee } from '@anticrm/contact'
|
||||
import type { AnyComponent } from '@anticrm/ui'
|
||||
|
||||
import workbench from '@anticrm/model-workbench'
|
||||
|
||||
import contact from '@anticrm/contact'
|
||||
import type { Doc, Domain, FindOptions, Ref } from '@anticrm/core'
|
||||
import { Builder, Model, Prop, TypeString, UX } from '@anticrm/model'
|
||||
import chunter from '@anticrm/model-chunter'
|
||||
import core, { TDoc, TSpace } from '@anticrm/model-core'
|
||||
import view from '@anticrm/model-view'
|
||||
import contact from '@anticrm/model-contact'
|
||||
import workbench from '@anticrm/model-workbench'
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import type { Project, Task } from '@anticrm/task'
|
||||
import task from './plugin'
|
||||
|
||||
@Model(task.class.Project, core.class.Space)
|
||||
@UX('Project' as IntlString, task.icon.Task)
|
||||
export class TProject extends TSpace implements Project {}
|
||||
|
||||
@Model(task.class.Task, core.class.Doc)
|
||||
@Model(task.class.Task, core.class.Doc, 'task' as Domain)
|
||||
@UX('Task' as IntlString, task.icon.Task, 'TASK' as IntlString)
|
||||
export class TTask extends TDoc implements Task {
|
||||
@Prop(TypeString(), 'Title' as IntlString)
|
||||
title!: string
|
||||
@Prop(TypeString(), 'No.' as IntlString)
|
||||
number!: number
|
||||
|
||||
@Prop(TypeString(), 'Name' as IntlString)
|
||||
name!: string
|
||||
|
||||
@Prop(TypeString(), 'Description' as IntlString)
|
||||
description!: string
|
||||
|
||||
@Prop(TypeString(), 'Assignee' as IntlString)
|
||||
assignee!: Ref<Employee>
|
||||
|
||||
@Prop(TypeString(), 'Comments' as IntlString)
|
||||
comments!: number
|
||||
|
||||
@Prop(TypeString(), 'Labels' as IntlString)
|
||||
labels!: string
|
||||
}
|
||||
|
||||
export function createModel (builder: Builder): void {
|
||||
@ -52,19 +60,6 @@ export function createModel (builder: Builder): void {
|
||||
}
|
||||
})
|
||||
|
||||
builder.createDoc(view.class.Viewlet, core.space.Model, {
|
||||
attachTo: task.class.Task,
|
||||
descriptor: view.viewlet.Table,
|
||||
open: 'ZX' as AnyComponent,
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
options: {
|
||||
lookup: {
|
||||
assignee: contact.class.Employee
|
||||
}
|
||||
} as FindOptions<Doc>,
|
||||
config: ['title', '$lookup.assignee']
|
||||
})
|
||||
|
||||
builder.createDoc(workbench.class.Application, core.space.Model, {
|
||||
label: task.string.ApplicationLabelTask,
|
||||
icon: task.icon.Task,
|
||||
@ -79,11 +74,45 @@ export function createModel (builder: Builder): void {
|
||||
}
|
||||
]
|
||||
}
|
||||
}, task.app.Tasks)
|
||||
|
||||
builder.createDoc(view.class.Viewlet, core.space.Model, {
|
||||
attachTo: task.class.Task,
|
||||
descriptor: view.viewlet.Table,
|
||||
open: task.component.EditTask,
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
options: {
|
||||
lookup: {
|
||||
assignee: contact.class.Employee
|
||||
}
|
||||
} as FindOptions<Doc>,
|
||||
config: [
|
||||
'',
|
||||
'name',
|
||||
'$lookup.assignee',
|
||||
{ presenter: chunter.component.AttachmentsPresenter, label: 'Files' },
|
||||
{ presenter: chunter.component.CommentsPresenter, label: 'Comments' },
|
||||
'modifiedOn'
|
||||
]
|
||||
})
|
||||
|
||||
builder.mixin(task.class.Task, core.class.Class, view.mixin.AttributePresenter, {
|
||||
presenter: task.component.TaskPresenter
|
||||
})
|
||||
|
||||
builder.mixin(task.class.Task, core.class.Class, view.mixin.ObjectEditor, {
|
||||
editor: task.component.EditTask
|
||||
})
|
||||
|
||||
builder.createDoc(task.class.Project, core.space.Model, {
|
||||
name: 'demo',
|
||||
description: 'Demo Project',
|
||||
name: 'public',
|
||||
description: 'Public tasks',
|
||||
private: false,
|
||||
members: []
|
||||
}, task.space.TasksPublic)
|
||||
|
||||
builder.createDoc(view.class.Sequence, view.space.Sequence, {
|
||||
attachedTo: task.class.Task,
|
||||
sequence: 0
|
||||
})
|
||||
}
|
||||
|
@ -14,26 +14,31 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { taskId } from '@anticrm/task'
|
||||
import task from '@anticrm/task-resources/src/plugin'
|
||||
import type { Ref, Space } from '@anticrm/core'
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import type { Ref, Class } from '@anticrm/core'
|
||||
import type { Project } from '@anticrm/task'
|
||||
import type { AnyComponent } from '@anticrm/ui'
|
||||
import { mergeIds } from '@anticrm/platform'
|
||||
import task, { taskId } from '@anticrm/task'
|
||||
import type { AnyComponent } from '@anticrm/ui'
|
||||
import { Application } from '@anticrm/workbench'
|
||||
|
||||
export default mergeIds(taskId, task, {
|
||||
app: {
|
||||
Tasks: '' as Ref<Application>
|
||||
},
|
||||
component: {
|
||||
ProjectView: '' as AnyComponent,
|
||||
CreateProject: '' as AnyComponent,
|
||||
CreateTask: '' as AnyComponent
|
||||
},
|
||||
class: {
|
||||
Project: '' as Ref<Class<Project>>
|
||||
CreateTask: '' as AnyComponent,
|
||||
EditTask: '' as AnyComponent,
|
||||
TaskPresenter: '' as AnyComponent
|
||||
},
|
||||
string: {
|
||||
Task: '' as IntlString,
|
||||
ApplicationLabelTask: '' as IntlString,
|
||||
Projects: '' as IntlString,
|
||||
CreateProject: '' as IntlString
|
||||
},
|
||||
space: {
|
||||
TasksPublic: '' as Ref<Space>
|
||||
}
|
||||
})
|
||||
|
@ -2,6 +2,19 @@
|
||||
"string": {
|
||||
"ApplicationLabelTask": "Tasks",
|
||||
"Projects": "Projects",
|
||||
"CreateProject": "New Project"
|
||||
"CreateProject": "New Project",
|
||||
"ProjectName": "Project",
|
||||
"MakePrivate": "Make Private",
|
||||
"MakePrivateDescription": "Only members can see it",
|
||||
"CreateTask": "Create task",
|
||||
"TaskProject": "selected project",
|
||||
"SelectProject": "Select project",
|
||||
"Task": "Task",
|
||||
"TaskName": "Task name *",
|
||||
"TaskAssignee": "Assignee",
|
||||
"TaskDescription": "Description",
|
||||
"UploadDropFilesHere": "Upload or drop files here",
|
||||
"NoAttachmentsForTask": "There are no attachments for this task.",
|
||||
"AssigneeRequired": "Assignee is required"
|
||||
}
|
||||
}
|
@ -13,10 +13,12 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { loadMetadata } from '@anticrm/platform'
|
||||
import task from '@anticrm/task'
|
||||
import { addStringsLoader, loadMetadata } from '@anticrm/platform'
|
||||
import task, {taskId} from '@anticrm/task'
|
||||
|
||||
const icons = require('../assets/icons.svg')
|
||||
loadMetadata(task.icon, {
|
||||
Task: `${icons}#task`,
|
||||
})
|
||||
|
||||
addStringsLoader(taskId, async (lang: string) => await import(`../lang/${lang}.json`))
|
||||
|
7
plugins/task-resources/.eslintrc.js
Normal file
7
plugins/task-resources/.eslintrc.js
Normal file
@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
extends: ['./node_modules/@anticrm/platform-rig/profiles/ui/config/eslint.config.json'],
|
||||
parserOptions: { tsconfigRootDir: __dirname },
|
||||
settings: {
|
||||
'svelte3/ignore-styles': () => true
|
||||
}
|
||||
};
|
@ -14,7 +14,19 @@
|
||||
"devDependencies": {
|
||||
"svelte-loader":"^3.1.2",
|
||||
"sass":"^1.37.5",
|
||||
"svelte-preprocess":"^4.7.4"
|
||||
"svelte-preprocess":"^4.7.4",
|
||||
"@anticrm/platform-rig":"~0.6.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
||||
"@typescript-eslint/parser": "^5.4.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",
|
||||
"svelte-check": "^2.2.10"
|
||||
},
|
||||
"dependencies": {
|
||||
"@anticrm/platform": "~0.6.5",
|
||||
@ -24,6 +36,11 @@
|
||||
"@anticrm/presentation": "~0.6.2",
|
||||
"@anticrm/text-editor": "~0.6.0",
|
||||
"@anticrm/contact": "~0.6.2",
|
||||
"@anticrm/core": "~0.6.11"
|
||||
"@anticrm/core": "~0.6.11",
|
||||
"@anticrm/chunter": "~0.6.1",
|
||||
"@anticrm/panel": "~0.6.0",
|
||||
"@anticrm/view": "~0.6.0",
|
||||
"@anticrm/view-resources": "~0.6.0",
|
||||
"@anticrm/login": "~0.6.1"
|
||||
}
|
||||
}
|
||||
|
138
plugins/task-resources/src/components/Attachments.svelte
Normal file
138
plugins/task-resources/src/components/Attachments.svelte
Normal file
@ -0,0 +1,138 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// 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 { Attachment } from '@anticrm/chunter'
|
||||
import chunter from '@anticrm/chunter'
|
||||
import type { Class, Doc, Ref, Space } from '@anticrm/core'
|
||||
import { setPlatformStatus, unknownError } from '@anticrm/platform'
|
||||
import { createQuery, getClient } from '@anticrm/presentation'
|
||||
import { CircleButton, IconAdd, Label, Spinner } from '@anticrm/ui'
|
||||
import { Table } from '@anticrm/view-resources'
|
||||
import { uploadFile } from '../utils'
|
||||
import UploadDuo from './icons/UploadDuo.svelte'
|
||||
import task from '../plugin'
|
||||
|
||||
export let objectId: Ref<Doc>
|
||||
export let space: Ref<Space>
|
||||
export let _class: Ref<Class<Doc>>
|
||||
|
||||
let attachments: Attachment[] = []
|
||||
|
||||
const query = createQuery()
|
||||
$: query.query(chunter.class.Attachment, { attachedTo: objectId }, result => { attachments = result })
|
||||
|
||||
let inputFile: HTMLInputElement
|
||||
let loading = 0
|
||||
|
||||
const client = getClient()
|
||||
|
||||
async function createAttachment (file: File) {
|
||||
loading++
|
||||
try {
|
||||
const uuid = await uploadFile(space, file, objectId)
|
||||
console.log('uploaded file uuid', uuid)
|
||||
client.addCollection(chunter.class.Attachment, space, objectId, _class, 'attachments', {
|
||||
name: file.name,
|
||||
file: uuid,
|
||||
type: file.type,
|
||||
size: file.size,
|
||||
lastModified: file.lastModified
|
||||
})
|
||||
} catch (err: any) {
|
||||
setPlatformStatus(unknownError(err))
|
||||
} finally {
|
||||
loading--
|
||||
}
|
||||
}
|
||||
|
||||
function fileSelected () {
|
||||
console.log(inputFile.files)
|
||||
const list = inputFile.files
|
||||
if (list === null || list.length === 0) return
|
||||
for (let index = 0; index < list.length; index++) {
|
||||
const file = list.item(index)
|
||||
if (file !== null) createAttachment(file)
|
||||
}
|
||||
}
|
||||
|
||||
function fileDrop (e: DragEvent) {
|
||||
const list = e.dataTransfer?.files
|
||||
if (list === undefined || list.length === 0) return
|
||||
for (let index = 0; index < list.length; index++) {
|
||||
const file = list.item(index)
|
||||
if (file !== null) createAttachment(file)
|
||||
}
|
||||
}
|
||||
|
||||
let dragover = false
|
||||
</script>
|
||||
|
||||
<div class="attachments-container">
|
||||
<div class="flex-row-center">
|
||||
<span class="title">Attachments</span>
|
||||
{#if loading}
|
||||
<Spinner/>
|
||||
{:else}
|
||||
<CircleButton icon={IconAdd} size={'small'} on:click={ () => { inputFile.click() } } />
|
||||
{/if}
|
||||
<input bind:this={inputFile} multiple type="file" name="file" id="file" style="display: none" on:change={fileSelected}/>
|
||||
</div>
|
||||
|
||||
{#if attachments.length === 0 && !loading}
|
||||
<div class="flex-col-center mt-5 zone-container" class:solid={dragover}
|
||||
on:dragover|preventDefault={ () => { dragover = true } }
|
||||
on:dragleave={ () => { dragover = false } }
|
||||
on:drop|preventDefault|stopPropagation={fileDrop}
|
||||
>
|
||||
<UploadDuo size={'large'} />
|
||||
<div class="small-text content-dark-color mt-2">
|
||||
<Label label={task.string.NoAttachmentsForTask} />
|
||||
</div>
|
||||
<div class="small-text">
|
||||
<a href={'#'} on:click={() => inputFile.click()}><Label label={task.string.UploadDropFilesHere} /></a>
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<Table
|
||||
_class={chunter.class.Attachment}
|
||||
config={['', 'lastModified']}
|
||||
options={ {} }
|
||||
query={ { attachedTo: objectId } }
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.attachments-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.title {
|
||||
margin-right: .75rem;
|
||||
font-weight: 500;
|
||||
font-size: 1.25rem;
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
}
|
||||
|
||||
.zone-container {
|
||||
padding: 1rem;
|
||||
color: var(--theme-caption-color);
|
||||
background: rgba(255, 255, 255, .03);
|
||||
border: 1px dashed rgba(255, 255, 255, .16);
|
||||
border-radius: .75rem;
|
||||
}
|
||||
</style>
|
56
plugins/task-resources/src/components/CreateProject.svelte
Normal file
56
plugins/task-resources/src/components/CreateProject.svelte
Normal file
@ -0,0 +1,56 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// 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 { createEventDispatcher } from 'svelte'
|
||||
import { IconFolder, EditBox, ToggleWithLabel, Grid } from '@anticrm/ui'
|
||||
|
||||
import { getClient, SpaceCreateCard } from '@anticrm/presentation'
|
||||
|
||||
import task from '../plugin'
|
||||
import core from '@anticrm/core'
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let name: string = ''
|
||||
let description: string = ''
|
||||
|
||||
export function canClose(): boolean {
|
||||
return name === ''
|
||||
}
|
||||
|
||||
const client = getClient()
|
||||
|
||||
function createProject() {
|
||||
client.createDoc(task.class.Project, core.space.Model, {
|
||||
name,
|
||||
description,
|
||||
private: false,
|
||||
members: []
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<SpaceCreateCard
|
||||
label={task.string.CreateProject}
|
||||
okAction={createProject}
|
||||
canSave={name ? true : false}
|
||||
on:close={() => { dispatch('close') }}
|
||||
>
|
||||
<Grid column={1} rowGap={1.5}>
|
||||
<EditBox label={task.string.ProjectName} icon={IconFolder} bind:value={name} placeholder={'Project name'} focus/>
|
||||
<ToggleWithLabel label={task.string.MakePrivate} description={task.string.MakePrivateDescription}/>
|
||||
</Grid>
|
||||
</SpaceCreateCard>
|
@ -14,46 +14,119 @@
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import contact, { Employee, EmployeeAccount } from '@anticrm/contact'
|
||||
import type { Data, Ref, Space } from '@anticrm/core'
|
||||
import { generateId } from '@anticrm/core'
|
||||
import { Card, getClient, UserBox } from '@anticrm/presentation'
|
||||
import { Task } from '@anticrm/task'
|
||||
import { EditBox, Grid, Status as StatusControl } from '@anticrm/ui'
|
||||
import { Status, OK, Severity } from '@anticrm/platform'
|
||||
import view from '@anticrm/view'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import type { Ref, Space } from '@anticrm/core'
|
||||
import { DatePicker, EditBox, Dialog, Tabs, Section, Grid, Row, TextArea, IconFile } from '@anticrm/ui'
|
||||
import { UserBox } from '@anticrm/presentation'
|
||||
import { ReferenceInput } from '@anticrm/text-editor'
|
||||
import type { Person } from '@anticrm/contact'
|
||||
|
||||
import { getClient } from '@anticrm/presentation'
|
||||
|
||||
import contact from '@anticrm/contact'
|
||||
import task from '../plugin'
|
||||
|
||||
export let space: Ref<Space>
|
||||
|
||||
let _space = space
|
||||
const status: Status = OK
|
||||
|
||||
let assignee: Ref<EmployeeAccount> // | null = null
|
||||
|
||||
const object: Data<Task> = {
|
||||
name: '',
|
||||
description: '',
|
||||
assignee: undefined as unknown as Ref<Employee>,
|
||||
number: 0
|
||||
}
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let title: string
|
||||
let assignee: Ref<Person>
|
||||
|
||||
const client = getClient()
|
||||
const taskId = generateId()
|
||||
|
||||
function createCandidate() {
|
||||
client.createDoc(task.class.Task, space, {
|
||||
title,
|
||||
export function canClose (): boolean {
|
||||
return object.name !== ''
|
||||
}
|
||||
|
||||
async function createTask () {
|
||||
const sequence = await client.findOne(view.class.Sequence, { attachedTo: task.class.Task })
|
||||
if (sequence === undefined) {
|
||||
throw new Error('sequence object not found')
|
||||
}
|
||||
|
||||
const incResult = await client.updateDoc(view.class.Sequence, view.space.Sequence, sequence._id, {
|
||||
$inc: { sequence: 1 }
|
||||
}, true)
|
||||
|
||||
const value: Data<Task> = {
|
||||
name: object.name,
|
||||
description: object.description,
|
||||
assignee,
|
||||
})
|
||||
number: (incResult as any).object.sequence
|
||||
}
|
||||
|
||||
await client.createDoc(task.class.Task, _space, value, taskId)
|
||||
dispatch('close')
|
||||
}
|
||||
</script>
|
||||
|
||||
<Dialog label={'Create Task'}
|
||||
okLabel={'Create Task'}
|
||||
okAction={createCandidate}
|
||||
on:close={() => { dispatch('close') }}>
|
||||
<Tabs/>
|
||||
<Section icon={IconFile} label={'General Information'}>
|
||||
<Grid>
|
||||
<Row><EditBox label={'Title *'} placeholder={'The Secret Project'} bind:value={title} focus /></Row>
|
||||
<UserBox _class={contact.class.Person} title='Assignee' caption='Employees' bind:value={assignee} />
|
||||
<DatePicker title={'Pick due date'} />
|
||||
<Row><ReferenceInput /></Row>
|
||||
</Grid>
|
||||
</Section>
|
||||
</Dialog>
|
||||
<!-- <DialogHeader {space} {object} {newValue} {resume} create={true} on:save={createCandidate}/> -->
|
||||
|
||||
<Card label={task.string.CreateTask}
|
||||
okAction={createTask}
|
||||
canSave={object.name.length > 0 && assignee !== undefined}
|
||||
spaceClass={task.class.Project}
|
||||
spaceLabel={task.string.ProjectName}
|
||||
spacePlaceholder={task.string.SelectProject}
|
||||
bind:space={_space}
|
||||
on:close={() => { dispatch('close') }}>
|
||||
<StatusControl slot="error" {status} />
|
||||
<Grid column={1} rowGap={1.5}>
|
||||
<EditBox label={task.string.TaskName} bind:value={object.name} icon={task.icon.Task} placeholder="The boring task" maxWidth="39rem" focus/>
|
||||
<UserBox _class={contact.class.EmployeeAccount} title='Assignee *' caption='Assign this task' bind:value={assignee} />
|
||||
</Grid>
|
||||
</Card>
|
||||
|
||||
<style lang="scss">
|
||||
.channels {
|
||||
margin-top: 1.25rem;
|
||||
span { margin-left: .5rem; }
|
||||
}
|
||||
|
||||
.locations {
|
||||
span {
|
||||
margin-bottom: .125rem;
|
||||
font-weight: 500;
|
||||
font-size: .75rem;
|
||||
color: var(--theme-content-accent-color);
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-top: .75rem;
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
}
|
||||
|
||||
.separator {
|
||||
margin: 1rem 0;
|
||||
height: 1px;
|
||||
background-color: var(--theme-card-divider);
|
||||
}
|
||||
|
||||
.resume {
|
||||
margin-top: 1rem;
|
||||
padding: .75rem;
|
||||
background: rgba(255, 255, 255, .05);
|
||||
border: 1px dashed rgba(255, 255, 255, .2);
|
||||
border-radius: .5rem;
|
||||
backdrop-filter: blur(10px);
|
||||
&.solid { border-style: solid; }
|
||||
}
|
||||
// .resume a {
|
||||
// font-size: .75rem;
|
||||
// color: var(--theme-content-dark-color);
|
||||
// &:hover { color: var(--theme-content-color); }
|
||||
// }
|
||||
</style>
|
||||
|
68
plugins/task-resources/src/components/EditTask.svelte
Normal file
68
plugins/task-resources/src/components/EditTask.svelte
Normal file
@ -0,0 +1,68 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// 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 { Ref } from '@anticrm/core'
|
||||
import { Panel } from '@anticrm/panel'
|
||||
import { createQuery, getClient } from '@anticrm/presentation'
|
||||
import type { Task } from '@anticrm/task'
|
||||
import { EditBox, Grid } from '@anticrm/ui'
|
||||
import view from '@anticrm/view'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import task from '../plugin'
|
||||
import Attachments from './Attachments.svelte'
|
||||
import TaskHeader from './TaskHeader.svelte'
|
||||
|
||||
export let _id: Ref<Task>
|
||||
let object: Task
|
||||
|
||||
const query = createQuery()
|
||||
$: query.query(task.class.Task, { _id }, result => { object = result[0] })
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const client = getClient()
|
||||
|
||||
function change (field: string, value: any) {
|
||||
client.updateDoc(task.class.Task, object.space, object._id, { [field]: value })
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if object !== undefined}
|
||||
<Panel icon={view.icon.Table} title={object.name} {object} on:close={() => { dispatch('close') }}>
|
||||
<TaskHeader {object} slot="subtitle" />
|
||||
|
||||
|
||||
<Grid column={1} rowGap={1.5}>
|
||||
<EditBox label={task.string.TaskName} bind:value={object.name} icon={task.icon.Task} placeholder="The boring task" maxWidth="39rem" focus on:change={(evt) => change('name', object.name)}/>
|
||||
<EditBox label={task.string.TaskDescription} bind:value={object.description} icon={task.icon.Task} placeholder="Description" maxWidth="39rem" on:change={(evt) => change('description', object.description)}/>
|
||||
</Grid>
|
||||
|
||||
<div class="mt-14">
|
||||
<Attachments objectId={object._id} _class={object._class} space={object.space} />
|
||||
</div>
|
||||
</Panel>
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
.attachments {
|
||||
margin-top: 3.5rem;
|
||||
}
|
||||
|
||||
.grid-cards {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
column-gap: 1.5rem;
|
||||
}
|
||||
</style>
|
41
plugins/task-resources/src/components/TaskHeader.svelte
Normal file
41
plugins/task-resources/src/components/TaskHeader.svelte
Normal file
@ -0,0 +1,41 @@
|
||||
<!--
|
||||
// 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 contact from '@anticrm/contact'
|
||||
import { getClient, UserBox } from '@anticrm/presentation'
|
||||
import { Task } from '@anticrm/task'
|
||||
import task from '../plugin'
|
||||
|
||||
export let object: Task
|
||||
const client = getClient()
|
||||
|
||||
function change () {
|
||||
client.updateDoc(object._class, object.space, object._id, { assignee: object.assignee })
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex-between header">
|
||||
<UserBox _class={contact.class.Employee} title={task.string.TaskAssignee} caption='Assignee' bind:value={object.assignee} on:change={change} />
|
||||
<!-- <AttributeBarEditor key={'state'} {object} showHeader={false} /> -->
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.header {
|
||||
width: 100%;
|
||||
padding: 0 .5rem;
|
||||
}
|
||||
</style>
|
39
plugins/task-resources/src/components/TaskPresenter.svelte
Normal file
39
plugins/task-resources/src/components/TaskPresenter.svelte
Normal file
@ -0,0 +1,39 @@
|
||||
<!--
|
||||
// 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 { Task } from '@anticrm/task'
|
||||
import { closeTooltip, Icon, showPopup } from '@anticrm/ui'
|
||||
import EditTask from './EditTask.svelte'
|
||||
import { getClient } from '@anticrm/presentation'
|
||||
import task from '../plugin'
|
||||
|
||||
export let value: Task
|
||||
|
||||
const client = getClient()
|
||||
const shortLabel = client.getHierarchy().getClass(value._class).shortLabel
|
||||
|
||||
function show () {
|
||||
closeTooltip()
|
||||
showPopup(EditTask, { _id: value._id }, 'full')
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<div class="sm-tool-icon" on:click={show}>
|
||||
<span class="icon"><Icon icon={task.icon.Task} size={'small'}/></span>{shortLabel}-{value.number}
|
||||
</div>
|
28
plugins/task-resources/src/components/icons/UploadDuo.svelte
Normal file
28
plugins/task-resources/src/components/icons/UploadDuo.svelte
Normal file
@ -0,0 +1,28 @@
|
||||
<!--
|
||||
// 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">
|
||||
export let size: 'small' | 'medium' | 'large'
|
||||
const fill: string = 'currentColor'
|
||||
</script>
|
||||
|
||||
<svg class="svg-{size}" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<path fill="var(--duotone-color)" d="M18,6.4c-0.1,0-0.2,0-0.3,0c-0.1,0-0.1,0-0.1,0c-0.1,0-0.1,0-0.1,0c0,0,0,0-0.1-0.1c0,0,0,0-0.1-0.1 c0-0.1-0.1-0.2-0.2-0.4c-0.9-1.9-2.8-3.3-5.1-3.3c-2.3,0-4.2,1.4-5.1,3.3C6.8,5.9,6.7,6,6.7,6.1c0,0.1-0.1,0.1-0.1,0.1 C6.6,6.3,6.6,6.3,6.5,6.3c0,0,0,0-0.1,0c0,0,0,0-0.1,0c-0.1,0-0.2,0-0.3,0C4,6.4,2.4,8,2.4,10S4,13.6,6,13.6h6h6 c2,0,3.6-1.6,3.6-3.6S20,6.4,18,6.4z"/>
|
||||
<g {fill}>
|
||||
<path d="M18,6.4c-0.1,0-0.2,0-0.3,0c-0.1,0-0.1,0-0.1,0c-0.1,0-0.1,0-0.1,0c0,0,0,0-0.1-0.1c0,0,0,0,0,0c0,0,0,0,0,0 c0,0,0,0,0,0c0,0,0,0,0,0c0,0,0,0-0.1-0.1c0-0.1-0.1-0.2-0.2-0.4c-0.9-1.9-2.8-3.3-5.1-3.3c-2.3,0-4.2,1.4-5.1,3.3 C6.8,5.9,6.7,6,6.7,6.1c0,0.1-0.1,0.1-0.1,0.1c0,0,0,0,0,0C6.6,6.3,6.6,6.3,6.5,6.3c0,0,0,0-0.1,0c0,0,0,0-0.1,0 c-0.1,0-0.2,0-0.3,0C4,6.4,2.4,8,2.4,10S4,13.6,6,13.6h0.6l1.2-1.2H6c-1.3,0-2.4-1.1-2.4-2.4c0-1.3,1.1-2.4,2.4-2.4h0.1 c0.2,0,0.4,0,0.6,0c0.2,0,0.4-0.1,0.6-0.2c0.2-0.1,0.3-0.3,0.4-0.4c0.1-0.1,0.1-0.2,0.2-0.3C7.8,6.5,7.9,6.4,8,6.2l0,0 c0.7-1.5,2.2-2.6,4-2.6s3.3,1.1,4,2.6l0,0c0.1,0.2,0.1,0.3,0.2,0.4c0,0.1,0.1,0.2,0.2,0.3c0.1,0.2,0.2,0.3,0.4,0.4 c0.2,0.1,0.4,0.2,0.6,0.2c0.2,0,0.4,0,0.6,0H18c1.3,0,2.4,1.1,2.4,2.4c0,1.3-1.1,2.4-2.4,2.4h-1.8l1.2,1.2H18c2,0,3.6-1.6,3.6-3.6 S20,6.4,18,6.4z"/>
|
||||
<path d="M12,11.2l-4.4,4.4l0.8,0.8l3-3V21c0,0.3,0.3,0.6,0.6,0.6s0.6-0.3,0.6-0.6v-7.6l3,3l0.8-0.8L12,11.2z"/>
|
||||
</g>
|
||||
</svg>
|
@ -14,10 +14,16 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import CreateTask from './components/CreateTask.svelte'
|
||||
import { Resources } from '@anticrm/platform'
|
||||
|
||||
export default async () => ({
|
||||
import CreateTask from './components/CreateTask.svelte'
|
||||
import CreateProject from './components/CreateProject.svelte'
|
||||
import TaskPresenter from './components/TaskPresenter.svelte'
|
||||
|
||||
export default async (): Promise<Resources> => ({
|
||||
component: {
|
||||
CreateTask
|
||||
},
|
||||
CreateTask,
|
||||
CreateProject,
|
||||
TaskPresenter
|
||||
}
|
||||
})
|
||||
|
@ -13,9 +13,28 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { mergeIds } from '@anticrm/platform'
|
||||
import { IntlString, mergeIds } from '@anticrm/platform'
|
||||
|
||||
import task, { taskId } from '@anticrm/task'
|
||||
|
||||
export default mergeIds(taskId, task, {
|
||||
string: {
|
||||
ApplicationLabelTask: '' as IntlString,
|
||||
Projects: '' as IntlString,
|
||||
CreateProject: '' as IntlString,
|
||||
ProjectName: '' as IntlString,
|
||||
MakePrivate: '' as IntlString,
|
||||
MakePrivateDescription: '' as IntlString,
|
||||
CreateTask: '' as IntlString,
|
||||
TaskProject: '' as IntlString,
|
||||
SelectProject: '' as IntlString,
|
||||
TaskName: '' as IntlString,
|
||||
TaskAssignee: '' as IntlString,
|
||||
TaskDescription: '' as IntlString,
|
||||
NoAttachmentsForTask: '' as IntlString,
|
||||
UploadDropFilesHere: '' as IntlString
|
||||
},
|
||||
status: {
|
||||
AssigneeRequired: '' as IntlString
|
||||
}
|
||||
})
|
||||
|
42
plugins/task-resources/src/utils.ts
Normal file
42
plugins/task-resources/src/utils.ts
Normal file
@ -0,0 +1,42 @@
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
import type { Doc, Ref, Space } from '@anticrm/core'
|
||||
import login from '@anticrm/login'
|
||||
import { getMetadata } from '@anticrm/platform'
|
||||
|
||||
export async function uploadFile (space: Ref<Space>, file: File, attachedTo: Ref<Doc>): Promise<string> {
|
||||
console.log(file)
|
||||
const uploadUrl = getMetadata(login.metadata.UploadUrl)
|
||||
|
||||
const data = new FormData()
|
||||
data.append('file', file)
|
||||
|
||||
const url = `${uploadUrl as string}?space=${space}&name=${encodeURIComponent(file.name)}&attachedTo=${attachedTo}`
|
||||
const resp = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + (getMetadata(login.metadata.LoginToken) as string)
|
||||
},
|
||||
body: data
|
||||
})
|
||||
if (resp.status !== 200) {
|
||||
throw new Error('Can\'t upload file.')
|
||||
}
|
||||
const uuid = await resp.text()
|
||||
console.log(uuid)
|
||||
return uuid
|
||||
}
|
@ -13,10 +13,10 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { plugin } from '@anticrm/platform'
|
||||
import type { Plugin, Asset } from '@anticrm/platform'
|
||||
import type { Space, Doc, Ref, Class } from '@anticrm/core'
|
||||
import type { Employee } from '@anticrm/contact'
|
||||
import type { Class, Doc, Ref, Space } from '@anticrm/core'
|
||||
import type { Asset, Plugin } from '@anticrm/platform'
|
||||
import { plugin } from '@anticrm/platform'
|
||||
|
||||
/**
|
||||
* @public
|
||||
@ -27,9 +27,15 @@ export interface Project extends Space {}
|
||||
* @public
|
||||
*/
|
||||
export interface Task extends Doc {
|
||||
title: string
|
||||
number: number // Sequence number
|
||||
|
||||
name: string
|
||||
description: string
|
||||
assignee: Ref<Employee>
|
||||
|
||||
comments?: number
|
||||
attachments?: number
|
||||
labels?: string
|
||||
}
|
||||
|
||||
/**
|
||||
@ -39,7 +45,8 @@ export const taskId = 'task' as Plugin
|
||||
|
||||
export default plugin(taskId, {
|
||||
class: {
|
||||
Task: '' as Ref<Class<Task>>
|
||||
Task: '' as Ref<Class<Task>>,
|
||||
Project: '' as Ref<Class<Project>>
|
||||
},
|
||||
icon: {
|
||||
Task: '' as Asset
|
||||
|
Loading…
Reference in New Issue
Block a user