Board application template (#1252)

Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
Andrey Sobolev 2022-04-02 10:49:23 +07:00 committed by GitHub
parent 6fcbd14d6f
commit e2ae4b157e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 1448 additions and 10 deletions

View File

@ -13,6 +13,9 @@ specifiers:
'@rush-temp/attachment': file:./projects/attachment.tgz '@rush-temp/attachment': file:./projects/attachment.tgz
'@rush-temp/attachment-assets': file:./projects/attachment-assets.tgz '@rush-temp/attachment-assets': file:./projects/attachment-assets.tgz
'@rush-temp/attachment-resources': file:./projects/attachment-resources.tgz '@rush-temp/attachment-resources': file:./projects/attachment-resources.tgz
'@rush-temp/board': file:./projects/board.tgz
'@rush-temp/board-assets': file:./projects/board-assets.tgz
'@rush-temp/board-resources': file:./projects/board-resources.tgz
'@rush-temp/calendar': file:./projects/calendar.tgz '@rush-temp/calendar': file:./projects/calendar.tgz
'@rush-temp/calendar-assets': file:./projects/calendar-assets.tgz '@rush-temp/calendar-assets': file:./projects/calendar-assets.tgz
'@rush-temp/calendar-resources': file:./projects/calendar-resources.tgz '@rush-temp/calendar-resources': file:./projects/calendar-resources.tgz
@ -53,6 +56,7 @@ specifiers:
'@rush-temp/model-activity': file:./projects/model-activity.tgz '@rush-temp/model-activity': file:./projects/model-activity.tgz
'@rush-temp/model-all': file:./projects/model-all.tgz '@rush-temp/model-all': file:./projects/model-all.tgz
'@rush-temp/model-attachment': file:./projects/model-attachment.tgz '@rush-temp/model-attachment': file:./projects/model-attachment.tgz
'@rush-temp/model-board': file:./projects/model-board.tgz
'@rush-temp/model-calendar': file:./projects/model-calendar.tgz '@rush-temp/model-calendar': file:./projects/model-calendar.tgz
'@rush-temp/model-chunter': file:./projects/model-chunter.tgz '@rush-temp/model-chunter': file:./projects/model-chunter.tgz
'@rush-temp/model-contact': file:./projects/model-contact.tgz '@rush-temp/model-contact': file:./projects/model-contact.tgz
@ -277,6 +281,9 @@ dependencies:
'@rush-temp/attachment': file:projects/attachment.tgz '@rush-temp/attachment': file:projects/attachment.tgz
'@rush-temp/attachment-assets': file:projects/attachment-assets.tgz_typescript@4.5.4 '@rush-temp/attachment-assets': file:projects/attachment-assets.tgz_typescript@4.5.4
'@rush-temp/attachment-resources': file:projects/attachment-resources.tgz_096c09b0b673a57c275d9767a12070b1 '@rush-temp/attachment-resources': file:projects/attachment-resources.tgz_096c09b0b673a57c275d9767a12070b1
'@rush-temp/board': file:projects/board.tgz
'@rush-temp/board-assets': file:projects/board-assets.tgz_typescript@4.5.4
'@rush-temp/board-resources': file:projects/board-resources.tgz_096c09b0b673a57c275d9767a12070b1
'@rush-temp/calendar': file:projects/calendar.tgz '@rush-temp/calendar': file:projects/calendar.tgz
'@rush-temp/calendar-assets': file:projects/calendar-assets.tgz_typescript@4.5.4 '@rush-temp/calendar-assets': file:projects/calendar-assets.tgz_typescript@4.5.4
'@rush-temp/calendar-resources': file:projects/calendar-resources.tgz_096c09b0b673a57c275d9767a12070b1 '@rush-temp/calendar-resources': file:projects/calendar-resources.tgz_096c09b0b673a57c275d9767a12070b1
@ -317,6 +324,7 @@ dependencies:
'@rush-temp/model-activity': file:projects/model-activity.tgz_typescript@4.5.4 '@rush-temp/model-activity': file:projects/model-activity.tgz_typescript@4.5.4
'@rush-temp/model-all': file:projects/model-all.tgz_typescript@4.5.4 '@rush-temp/model-all': file:projects/model-all.tgz_typescript@4.5.4
'@rush-temp/model-attachment': file:projects/model-attachment.tgz_typescript@4.5.4 '@rush-temp/model-attachment': file:projects/model-attachment.tgz_typescript@4.5.4
'@rush-temp/model-board': file:projects/model-board.tgz_typescript@4.5.4
'@rush-temp/model-calendar': file:projects/model-calendar.tgz_typescript@4.5.4 '@rush-temp/model-calendar': file:projects/model-calendar.tgz_typescript@4.5.4
'@rush-temp/model-chunter': file:projects/model-chunter.tgz_typescript@4.5.4 '@rush-temp/model-chunter': file:projects/model-chunter.tgz_typescript@4.5.4
'@rush-temp/model-contact': file:projects/model-contact.tgz_typescript@4.5.4 '@rush-temp/model-contact': file:projects/model-contact.tgz_typescript@4.5.4
@ -11486,6 +11494,83 @@ packages:
- supports-color - supports-color
dev: false dev: false
file:projects/board-assets.tgz_typescript@4.5.4:
resolution: {integrity: sha512-0P80l5fx90GJ+nn83KKv4d8iVFWH2LxAkqadAbFbcHzEEvoIA7IyPigq1egkrXMe7DB6cMBbFYT2j1bIu2cL8w==, tarball: file:projects/board-assets.tgz}
id: file:projects/board-assets.tgz
name: '@rush-temp/board-assets'
version: 0.0.0
dependencies:
'@rushstack/heft': 0.41.8
'@types/heft-jest': 1.0.2
'@types/node': 16.11.14
'@typescript-eslint/eslint-plugin': 5.7.0_c25e8c1f4f4f7aaed27aa6f9ce042237
'@typescript-eslint/parser': 5.7.0_eslint@7.32.0+typescript@4.5.4
eslint: 7.32.0
eslint-config-standard-with-typescript: 21.0.1_ce2fa0c4dfa1c256100cababd749a13a
eslint-plugin-import: 2.25.3_eslint@7.32.0
eslint-plugin-node: 11.1.0_eslint@7.32.0
eslint-plugin-promise: 5.2.0_eslint@7.32.0
prettier: 2.5.1
transitivePeerDependencies:
- supports-color
- typescript
dev: false
file:projects/board-resources.tgz_096c09b0b673a57c275d9767a12070b1:
resolution: {integrity: sha512-h7C6EVXg0kr1eAHQ6ZNFbbCjs2WdGES1ptim4CFWEEkiFOCSZHeta5h84pD/sy0SE5Ku9O2ZMM/+J5RvOqblgA==, tarball: file:projects/board-resources.tgz}
id: file:projects/board-resources.tgz
name: '@rush-temp/board-resources'
version: 0.0.0
dependencies:
'@typescript-eslint/eslint-plugin': 5.7.0_c25e8c1f4f4f7aaed27aa6f9ce042237
'@typescript-eslint/parser': 5.7.0_eslint@7.32.0+typescript@4.5.4
eslint: 7.32.0
eslint-config-standard-with-typescript: 21.0.1_ce2fa0c4dfa1c256100cababd749a13a
eslint-plugin-import: 2.25.3_eslint@7.32.0
eslint-plugin-node: 11.1.0_eslint@7.32.0
eslint-plugin-promise: 5.2.0_eslint@7.32.0
eslint-plugin-svelte3: 3.2.1_eslint@7.32.0+svelte@3.44.3
prettier: 2.5.1
prettier-plugin-svelte: 2.5.1_prettier@2.5.1+svelte@3.44.3
sass: 1.45.0
svelte: 3.44.3
svelte-check: 2.3.0_4374c622c67ed7479ff0e44c29d09bce
svelte-loader: 3.1.2_svelte@3.44.3
svelte-preprocess: 4.10.3_14d64cad431e31f100de7363af24a44f
typescript: 4.5.4
transitivePeerDependencies:
- '@babel/core'
- coffeescript
- less
- node-sass
- postcss
- postcss-load-config
- pug
- stylus
- sugarss
- supports-color
dev: false
file:projects/board.tgz:
resolution: {integrity: sha512-K6XdiXv9w+xvcegm1Ql7XmBXIR/nMElWROWkVabz/SGhrvmENtjOa6mKVZploQf5cTafItd1V2e/NxZu8DnrgA==, tarball: file:projects/board.tgz}
name: '@rush-temp/board'
version: 0.0.0
dependencies:
'@rushstack/heft': 0.41.8
'@types/heft-jest': 1.0.2
'@typescript-eslint/eslint-plugin': 5.7.0_c25e8c1f4f4f7aaed27aa6f9ce042237
'@typescript-eslint/parser': 5.7.0_eslint@7.32.0+typescript@4.5.4
eslint: 7.32.0
eslint-config-standard-with-typescript: 21.0.1_ce2fa0c4dfa1c256100cababd749a13a
eslint-plugin-import: 2.25.3_eslint@7.32.0
eslint-plugin-node: 11.1.0_eslint@7.32.0
eslint-plugin-promise: 5.2.0_eslint@7.32.0
prettier: 2.5.1
typescript: 4.5.4
transitivePeerDependencies:
- supports-color
dev: false
file:projects/calendar-assets.tgz_typescript@4.5.4: file:projects/calendar-assets.tgz_typescript@4.5.4:
resolution: {integrity: sha512-muyoJ0EuKPUpsAEL1bLgdR90OqIoohgdfUFDwyWP1qmtAe9k1my76bJSIiU1JSfybyssHYiR8jpM/SuIonWg3Q==, tarball: file:projects/calendar-assets.tgz} resolution: {integrity: sha512-muyoJ0EuKPUpsAEL1bLgdR90OqIoohgdfUFDwyWP1qmtAe9k1my76bJSIiU1JSfybyssHYiR8jpM/SuIonWg3Q==, tarball: file:projects/calendar-assets.tgz}
id: file:projects/calendar-assets.tgz id: file:projects/calendar-assets.tgz
@ -12495,6 +12580,27 @@ packages:
- typescript - typescript
dev: false dev: false
file:projects/model-board.tgz_typescript@4.5.4:
resolution: {integrity: sha512-FbrtTOpKvWXViGyZIPanFC9gKghqsghpu2Dm4NV0SGFAWvz37/gh4Om2pfqGOcOcwTftsIvpsHzJGLio+stnVQ==, tarball: file:projects/model-board.tgz}
id: file:projects/model-board.tgz
name: '@rush-temp/model-board'
version: 0.0.0
dependencies:
'@rushstack/heft': 0.41.8
'@types/heft-jest': 1.0.2
'@typescript-eslint/eslint-plugin': 5.7.0_c25e8c1f4f4f7aaed27aa6f9ce042237
'@typescript-eslint/parser': 5.7.0_eslint@7.32.0+typescript@4.5.4
eslint: 7.32.0
eslint-config-standard-with-typescript: 21.0.1_ce2fa0c4dfa1c256100cababd749a13a
eslint-plugin-import: 2.25.3_eslint@7.32.0
eslint-plugin-node: 11.1.0_eslint@7.32.0
eslint-plugin-promise: 5.2.0_eslint@7.32.0
prettier: 2.5.1
transitivePeerDependencies:
- supports-color
- typescript
dev: false
file:projects/model-calendar.tgz_typescript@4.5.4: file:projects/model-calendar.tgz_typescript@4.5.4:
resolution: {integrity: sha512-1WD+gs/bHwfYdQWeuSL9DSwEZ6eGXJZQ5uIUdwQJMr8OUsKFTzIjou8X81QC5jd2LUR/c+Gdl2zbVVeOxXDflg==, tarball: file:projects/model-calendar.tgz} resolution: {integrity: sha512-1WD+gs/bHwfYdQWeuSL9DSwEZ6eGXJZQ5uIUdwQJMr8OUsKFTzIjou8X81QC5jd2LUR/c+Gdl2zbVVeOxXDflg==, tarball: file:projects/model-calendar.tgz}
id: file:projects/model-calendar.tgz id: file:projects/model-calendar.tgz
@ -13506,7 +13612,7 @@ packages:
dev: false dev: false
file:projects/prod-tracker.tgz_a07ec81d4d975778878ca12202ea119e: file:projects/prod-tracker.tgz_a07ec81d4d975778878ca12202ea119e:
resolution: {integrity: sha512-ml5yu/H4Tqliw+NJQ3SJtajDjqJe+bMRtmG/yU0C7Yktuiz1KefgUnIzftkpLoVx1tFQhs9hLkIG2dYLp0GgPg==, tarball: file:projects/prod-tracker.tgz} resolution: {integrity: sha512-dl5eoirwPVY6dcl4eNTnk0BUpGnXVxppdq2EQd1S81HGk0zT+2X76KJaZ3sUf7byks3kNFl4rFmWOn+JLrpXNA==, tarball: file:projects/prod-tracker.tgz}
id: file:projects/prod-tracker.tgz id: file:projects/prod-tracker.tgz
name: '@rush-temp/prod-tracker' name: '@rush-temp/prod-tracker'
version: 0.0.0 version: 0.0.0
@ -13552,7 +13658,7 @@ packages:
dev: false dev: false
file:projects/prod.tgz_a07ec81d4d975778878ca12202ea119e: file:projects/prod.tgz_a07ec81d4d975778878ca12202ea119e:
resolution: {integrity: sha512-nDyFjQ3sOea0YCtOVvhhquRWOZi521nMCYd2ClE8AEtL5d7gIAkCgqVROEpOVVuNppMm0f+m77pmeg409J+Cgw==, tarball: file:projects/prod.tgz} resolution: {integrity: sha512-KLlfoNhRQ0ANPcIvDVyVVK9BZovDWIXjZ95QuSbES38inv0bsKlk0kIZMhfp9OWQ2qPYIifJc5uOB+zcy5FUkg==, tarball: file:projects/prod.tgz}
id: file:projects/prod.tgz id: file:projects/prod.tgz
name: '@rush-temp/prod' name: '@rush-temp/prod'
version: 0.0.0 version: 0.0.0

View File

@ -135,6 +135,9 @@
"@anticrm/tracker": "~0.6.0", "@anticrm/tracker": "~0.6.0",
"@anticrm/tracker-assets": "~0.6.0", "@anticrm/tracker-assets": "~0.6.0",
"@anticrm/tracker-resources": "~0.6.0", "@anticrm/tracker-resources": "~0.6.0",
"@anticrm/text-editor": "~0.6.0" "@anticrm/text-editor": "~0.6.0",
"@anticrm/board": "~0.6.0",
"@anticrm/board-assets": "~0.6.0",
"@anticrm/board-resources": "~0.6.0"
} }
} }

View File

@ -37,6 +37,7 @@ import { notificationId } from '@anticrm/notification'
import { tagsId } from '@anticrm/tags' import { tagsId } from '@anticrm/tags'
import { calendarId } from '@anticrm/calendar' import { calendarId } from '@anticrm/calendar'
import { trackerId } from '@anticrm/tracker' import { trackerId } from '@anticrm/tracker'
import { boardId } from '@anticrm/board'
import rekoni from '@anticrm/rekoni' import rekoni from '@anticrm/rekoni'
import '@anticrm/login-assets' import '@anticrm/login-assets'
@ -58,6 +59,7 @@ import '@anticrm/notification-assets'
import '@anticrm/tags-assets' import '@anticrm/tags-assets'
import '@anticrm/calendar-assets' import '@anticrm/calendar-assets'
import '@anticrm/tracker-assets' import '@anticrm/tracker-assets'
import '@anticrm/board-assets'
import presentation, { presentationId } from '@anticrm/presentation' import presentation, { presentationId } from '@anticrm/presentation'
import { coreId } from '@anticrm/core' import { coreId } from '@anticrm/core'
import { textEditorId } from '@anticrm/text-editor' import { textEditorId } from '@anticrm/text-editor'
@ -110,6 +112,7 @@ export async function configurePlatform() {
addLocation(calendarId, () => import(/* webpackChunkName: "calendar" */ '@anticrm/calendar-resources')) addLocation(calendarId, () => import(/* webpackChunkName: "calendar" */ '@anticrm/calendar-resources'))
addLocation(trackerId, () => import(/* webpackChunkName: "tracker" */ '@anticrm/tracker-resources')) addLocation(trackerId, () => import(/* webpackChunkName: "tracker" */ '@anticrm/tracker-resources'))
addLocation(boardId, () => import(/* webpackChunkName: "board" */ '@anticrm/board-resources'))
setMetadata(workbench.metadata.PlatformTitle, 'Platform') setMetadata(workbench.metadata.PlatformTitle, 'Platform')
} }

View File

@ -67,6 +67,7 @@
"@anticrm/model-server-calendar": "~0.6.0", "@anticrm/model-server-calendar": "~0.6.0",
"@anticrm/model-server-gmail": "~0.6.0", "@anticrm/model-server-gmail": "~0.6.0",
"@anticrm/model-server-telegram": "~0.6.0", "@anticrm/model-server-telegram": "~0.6.0",
"@anticrm/model-tracker": "~0.6.0" "@anticrm/model-tracker": "~0.6.0",
"@anticrm/model-board": "~0.6.0"
} }
} }

View File

@ -19,6 +19,7 @@ import { createDeps as createLeadDeps } from '@anticrm/model-lead'
import { createDeps as createRecruitDeps } from '@anticrm/model-recruit' import { createDeps as createRecruitDeps } from '@anticrm/model-recruit'
import { createDeps as createDemoDeps } from '@anticrm/model-demo' import { createDeps as createDemoDeps } from '@anticrm/model-demo'
import { createDeps as createTrackerDeps } from '@anticrm/model-tracker' import { createDeps as createTrackerDeps } from '@anticrm/model-tracker'
import { createDeps as createBoardDeps } from '@anticrm/model-board'
export async function createDeps (client: Client): Promise<void> { export async function createDeps (client: Client): Promise<void> {
await createTaskDeps(client) await createTaskDeps(client)
@ -26,4 +27,5 @@ export async function createDeps (client: Client): Promise<void> {
await createRecruitDeps(client) await createRecruitDeps(client)
await createDemoDeps(client) await createDemoDeps(client)
await createTrackerDeps(client) await createTrackerDeps(client)
await createBoardDeps(client)
} }

View File

@ -53,6 +53,7 @@ import { createModel as serverCalendarModel } from '@anticrm/model-server-calend
import { createModel as serverGmailModel } from '@anticrm/model-server-gmail' import { createModel as serverGmailModel } from '@anticrm/model-server-gmail'
import { createModel as serverTelegramModel } from '@anticrm/model-server-telegram' import { createModel as serverTelegramModel } from '@anticrm/model-server-telegram'
import { createModel as trackerModel } from '@anticrm/model-tracker' import { createModel as trackerModel } from '@anticrm/model-tracker'
import { createModel as boardModel } from '@anticrm/model-board'
export const version: Data<Version> = jsonVersion as Data<Version> export const version: Data<Version> = jsonVersion as Data<Version>
@ -95,7 +96,8 @@ const builders: [(b: Builder) => void, string][] = [
[serverGmailModel, 'server-gmail'], [serverGmailModel, 'server-gmail'],
[serverTelegramModel, 'server-telegram'], [serverTelegramModel, 'server-telegram'],
[trackerModel, 'tracker'], [trackerModel, 'tracker'],
[createDemo, 'demo'] [createDemo, 'demo'],
[boardModel, 'board']
] ]
for (const [b, id] of builders) { for (const [b, id] of builders) {

View File

@ -30,6 +30,7 @@ import { telegramOperation } from '@anticrm/model-telegram'
import { templatesOperation } from '@anticrm/model-templates' import { templatesOperation } from '@anticrm/model-templates'
import { viewOperation } from '@anticrm/model-view' import { viewOperation } from '@anticrm/model-view'
import { trackerOperation } from '@anticrm/model-tracker' import { trackerOperation } from '@anticrm/model-tracker'
import { boardOperation } from '@anticrm/model-board'
export const migrateOperations: MigrateOperation[] = [ export const migrateOperations: MigrateOperation[] = [
coreOperation, coreOperation,
@ -46,5 +47,6 @@ export const migrateOperations: MigrateOperation[] = [
tagsOperation, tagsOperation,
notificationOperation, notificationOperation,
settingOperation, settingOperation,
trackerOperation trackerOperation,
boardOperation
] ]

View File

@ -0,0 +1,7 @@
module.exports = {
extends: ['./node_modules/@anticrm/model-rig/profiles/default/config/eslint.config.json'],
parserOptions: {
tsconfigRootDir: __dirname,
project: './tsconfig.json'
}
}

4
models/board/.npmignore Normal file
View File

@ -0,0 +1,4 @@
*
!/lib/**
!CHANGELOG.md
/lib/**/__tests__/

View File

@ -0,0 +1,18 @@
// The "rig.json" file directs tools to look for their config files in an external package.
// Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package
{
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
/**
* (Required) The name of the rig package to inherit from.
* It should be an NPM package name with the "-rig" suffix.
*/
"rigPackageName": "@anticrm/model-rig"
/**
* (Optional) Selects a config profile from the rig package. The name must consist of
* lowercase alphanumeric words separated by hyphens, for example "sample-profile".
* If omitted, then the "default" profile will be used."
*/
// "rigProfile": "your-profile-name"
}

46
models/board/package.json Normal file
View File

@ -0,0 +1,46 @@
{
"name": "@anticrm/model-board",
"version": "0.6.0",
"main": "lib/index.js",
"author": "Anticrm Platform Contributors",
"license": "EPL-2.0",
"scripts": {
"build": "heft build",
"build:watch": "tsc",
"lint:fix": "eslint --fix src",
"lint": "eslint src",
"format": "prettier --write src && eslint --fix src"
},
"devDependencies": {
"@anticrm/model-rig": "~0.6.0",
"@typescript-eslint/eslint-plugin": "^5.4.0",
"eslint-plugin-import": "^2.25.3",
"eslint-plugin-promise": "^5.1.1",
"eslint-plugin-node": "^11.1.0",
"eslint": "^7.32.0",
"@types/heft-jest": "^1.0.2",
"@typescript-eslint/parser": "^5.4.0",
"eslint-config-standard-with-typescript": "^21.0.1",
"prettier": "^2.4.1",
"@rushstack/heft": "^0.41.1"
},
"dependencies": {
"@anticrm/core": "~0.6.16",
"@anticrm/model": "~0.6.0",
"@anticrm/ui": "~0.6.0",
"@anticrm/contact": "~0.6.5",
"@anticrm/platform": "~0.6.5",
"@anticrm/model-core": "~0.6.0",
"@anticrm/model-view": "~0.6.0",
"@anticrm/model-workbench": "~0.6.1",
"@anticrm/model-contact": "~0.6.1",
"@anticrm/model-chunter": "~0.6.0",
"@anticrm/model-attachment": "~0.6.0",
"@anticrm/board": "~0.6.0",
"@anticrm/board-resources": "~0.6.0",
"@anticrm/view": "~0.6.0",
"@anticrm/task": "~0.6.0",
"@anticrm/model-task": "~0.6.0",
"@anticrm/workbench": "~0.6.1"
}
}

View File

@ -0,0 +1,63 @@
//
// Copyright © 2020, 2021 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.
//
import core, { Doc, Space, TxOperations } from '@anticrm/core'
import type { Client, Ref } from '@anticrm/core'
import task, { createKanban } from '@anticrm/task'
import type { KanbanTemplate } from '@anticrm/task'
import { createKanbanTemplate } from '@anticrm/model-task'
import board from './plugin'
export async function createDeps (client: Client): Promise<void> {
const tx = new TxOperations(client, core.account.System)
if ((await tx.findOne(task.class.Sequence, { _id: board.ids.Sequence })) === undefined) {
await tx.createDoc(
task.class.Sequence,
task.space.Sequence,
{
attachedTo: board.class.Card,
sequence: 0
},
board.ids.Sequence
)
}
if ((await tx.findOne(task.class.KanbanTemplate, { _id: board.template.DefaultBoard })) === undefined) {
const defaultTmpl = await createDefaultKanbanTemplate(tx)
await createKanban(tx, board.space.DefaultBoard, defaultTmpl)
}
}
const defaultKanban = {
states: [
{ color: 9, title: 'To do' },
{ color: 9, title: 'Done' }
],
doneStates: [
{ isWon: true, title: 'Won' },
{ isWon: false, title: 'Lost' }
]
}
async function createDefaultKanbanTemplate (client: TxOperations): Promise<Ref<KanbanTemplate>> {
return await createKanbanTemplate(client, {
kanbanId: board.template.DefaultBoard,
space: board.space.BoardTemplates as Ref<Doc> as Ref<Space>,
title: 'Default board',
states: defaultKanban.states,
doneStates: defaultKanban.doneStates
})
}

183
models/board/src/index.ts Normal file
View File

@ -0,0 +1,183 @@
//
// 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.
//
// To help typescript locate view plugin properly
import type { Board, Card } from '@anticrm/board'
import type { Employee } from '@anticrm/contact'
import { Doc, FindOptions, IndexKind, Ref } from '@anticrm/core'
import { Builder, Collection, Index, Model, Prop, TypeMarkup, TypeRef, TypeString, UX } from '@anticrm/model'
import attachment from '@anticrm/model-attachment'
import chunter from '@anticrm/model-chunter'
import contact from '@anticrm/model-contact'
import core from '@anticrm/model-core'
import task, { TSpaceWithStates, TTask } from '@anticrm/model-task'
import view from '@anticrm/model-view'
import workbench from '@anticrm/model-workbench'
import type {} from '@anticrm/view'
import board from './plugin'
@Model(board.class.Board, task.class.SpaceWithStates)
@UX(board.string.Board, board.icon.Board)
export class TBoard extends TSpaceWithStates implements Board {
color!: number
background!: string
}
@Model(board.class.Card, task.class.Task)
@UX(board.string.Card, board.icon.Card, undefined, 'title')
export class TCard extends TTask implements Card {
@Prop(TypeString(), board.string.Title)
@Index(IndexKind.FullText)
title!: string
@Prop(TypeMarkup(), board.string.Description)
@Index(IndexKind.FullText)
description!: string
@Prop(TypeString(), board.string.Location)
@Index(IndexKind.FullText)
location!: string
@Prop(Collection(chunter.class.Comment), chunter.string.Comments)
comments?: number
@Prop(Collection(attachment.class.Attachment), attachment.string.Attachments)
attachments?: number
@Prop(TypeRef(contact.class.Employee), board.string.Assignee)
declare assignee: Ref<Employee> | null
@Prop(Collection(contact.class.Employee), board.string.Members)
members!: Ref<Employee>[]
}
export function createModel (builder: Builder): void {
builder.createModel(TBoard, TCard)
builder.mixin(board.class.Board, core.class.Class, workbench.mixin.SpaceView, {
view: {
class: board.class.Card,
createItemDialog: board.component.CreateCard,
createItemLabel: board.string.CardCreateLabel
}
})
builder.createDoc(
workbench.class.Application,
core.space.Model,
{
label: board.string.BoardApplication,
icon: board.icon.Board,
hidden: false,
navigatorModel: {
specials: [
{
id: 'boards',
label: board.string.Boards,
icon: board.icon.Board,
component: board.component.Boards,
position: 'top'
},
{
id: 'members',
label: board.string.Members,
icon: board.icon.Board,
component: board.component.Members,
position: 'top'
},
{
id: 'settings',
label: board.string.Settings,
icon: board.icon.Board,
component: board.component.Settings,
position: 'top'
}
],
spaces: [
{
label: board.string.MyBoards,
spaceClass: board.class.Board,
addSpaceLabel: board.string.BoardCreateLabel,
createComponent: board.component.CreateBoard
}
]
}
},
board.app.Board
)
// const leadLookup: Lookup<Card> =
// {
// state: task.class.State,
// doneState: task.class.DoneState
// }
// builder.createDoc(view.class.Viewlet, core.space.Model, {
// attachTo: board.class.Card,
// descriptor: task.viewlet.StatusTable,
// // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
// options: {
// lookup: leadLookup
// } as FindOptions<Doc>, // TODO: fix
// config: [
// '',
// '$lookup.attachedTo',
// '$lookup.state',
// '$lookup.doneState',
// { presenter: attachment.component.AttachmentsPresenter, label: attachment.string.Files, sortingKey: 'attachments' },
// { presenter: chunter.component.CommentsPresenter, label: chunter.string.Comments, sortingKey: 'comments' },
// 'modifiedOn',
// '$lookup.attachedTo.$lookup.channels'
// ]
// })
builder.createDoc(view.class.Viewlet, core.space.Model, {
attachTo: board.class.Card,
descriptor: task.viewlet.Kanban,
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
options: {
lookup: {}
} as FindOptions<Doc>, // TODO: fix
config: []
})
builder.mixin(board.class.Card, core.class.Class, task.mixin.KanbanCard, {
card: board.component.KanbanCard
})
builder.mixin(board.class.Card, core.class.Class, view.mixin.ObjectEditor, {
editor: board.component.EditCard
})
builder.mixin(board.class.Card, core.class.Class, view.mixin.AttributePresenter, {
presenter: board.component.CardPresenter
})
builder.createDoc(
task.class.KanbanTemplateSpace,
core.space.Model,
{
name: board.string.Boards,
description: board.string.ManageBoardStatuses,
icon: board.component.TemplatesIcon
},
board.space.BoardTemplates
)
}
export { createDeps } from './creation'
export { boardOperation } from './migration'
export { default } from './plugin'

View File

@ -0,0 +1,51 @@
//
// 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 { TxOperations } from '@anticrm/core'
import { MigrateOperation, MigrationClient, MigrationUpgradeClient } from '@anticrm/model'
import core from '@anticrm/model-core'
import { createDeps } from './creation'
import board from './plugin'
async function createSpace (tx: TxOperations): Promise<void> {
const current = await tx.findOne(core.class.Space, {
_id: board.space.DefaultBoard
})
if (current === undefined) {
await tx.createDoc(
board.class.Board,
core.space.Space,
{
name: 'Default',
description: 'Default board',
private: false,
archived: false,
members: []
},
board.space.DefaultBoard
)
}
}
export const boardOperation: MigrateOperation = {
async migrate (client: MigrationClient): Promise<void> {
},
async upgrade (client: MigrationUpgradeClient): Promise<void> {
const ops = new TxOperations(client, core.account.System)
await createSpace(ops)
await createDeps(ops)
}
}

View File

@ -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.
//
import { boardId } from '@anticrm/board'
import board from '@anticrm/board-resources/src/plugin'
import type { Ref, Space } from '@anticrm/core'
import { mergeIds } from '@anticrm/platform'
import { KanbanTemplate, Sequence } from '@anticrm/task'
import type { AnyComponent } from '@anticrm/ui'
export default mergeIds(boardId, board, {
component: {
CreateBoard: '' as AnyComponent,
CreateCard: '' as AnyComponent,
EditCard: '' as AnyComponent,
KanbanCard: '' as AnyComponent,
CardPresenter: '' as AnyComponent,
TemplatesIcon: '' as AnyComponent,
Cards: '' as AnyComponent
},
space: {
DefaultBoard: '' as Ref<Space>
},
template: {
DefaultBoard: '' as Ref<KanbanTemplate>
},
ids: {
Sequence: '' as Ref<Sequence>
}
})

View File

@ -0,0 +1,8 @@
{
"extends": "./node_modules/@anticrm/model-rig/profiles/default/tsconfig.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./lib",
}
}

View File

@ -0,0 +1,7 @@
module.exports = {
extends: ['./node_modules/@anticrm/platform-rig/profiles/default/config/eslint.config.json'],
parserOptions: {
tsconfigRootDir: __dirname,
project: './tsconfig.json'
}
}

View File

@ -0,0 +1,10 @@
<!-- ALL HASHTAGs -->
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<symbol id="board" viewBox="0 0 16 16">
<path d="M13,1h-2.2H9.4H6.6H5.2H3C1.9,1,1,1.9,1,3v10c0,1.1,0.9,2,2,2h2.2h1.4h2.8h1.4H13c1.1,0,2-0.9,2-2V3C15,1.9,14.1,1,13,1z M3,13.8c-0.4,0-0.8-0.4-0.8-0.8V3c0-0.4,0.4-0.8,0.8-0.8h2.2v11.6H3z M6.6,13.8V2.2h2.8v11.6H6.6z M13.8,13c0,0.4-0.4,0.8-0.8,0.8 h-2.2V2.2H13c0.4,0,0.8,0.4,0.8,0.8V13z"/>
</symbol>
<symbol id="card" viewBox="0 0 24 24">
<path d="M21.4,3.1c-0.2-0.2-0.6-0.2-0.8,0L11.1,13l-2.3-2.4c-0.2-0.2-0.6-0.2-0.8,0s-0.2,0.6,0,0.8l2.7,2.8 c0.1,0.1,0.3,0.2,0.4,0.2s0.3-0.1,0.4-0.2l9.9-10.4C21.7,3.7,21.7,3.3,21.4,3.1z"/>
<path d="M19.2,11.4c-0.3,0-0.6,0.3-0.6,0.6v6.6c0,0.7-0.5,1.3-1.2,1.3H4.8c-0.7,0-1.2-0.6-1.2-1.3V5.4 c0-0.7,0.5-1.3,1.2-1.3h9.9c0.3,0,0.6-0.3,0.6-0.6S15,2.9,14.7,2.9H4.8C3.5,2.9,2.4,4,2.4,5.4v13.2c0,1.4,1.1,2.5,2.4,2.5h12.6 c1.3,0,2.4-1.1,2.4-2.5V12C19.8,11.7,19.5,11.4,19.2,11.4z"/>
</symbol>
</svg>

After

Width:  |  Height:  |  Size: 977 B

View File

@ -0,0 +1,18 @@
// The "rig.json" file directs tools to look for their config files in an external package.
// Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package
{
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
/**
* (Required) The name of the rig package to inherit from.
* It should be an NPM package name with the "-rig" suffix.
*/
"rigPackageName": "@anticrm/platform-rig"
/**
* (Optional) Selects a config profile from the rig package. The name must consist of
* lowercase alphanumeric words separated by hyphens, for example "sample-profile".
* If omitted, then the "default" profile will be used."
*/
// "rigProfile": "your-profile-name"
}

View File

@ -0,0 +1,28 @@
{
"string": {
"CreateBoard": "Create board",
"CreateCard": "Create card",
"CardName": "Card name",
"Cards": "Cards",
"SelectBoard": "Select board",
"More": "More...",
"Title": "Title",
"ManageBoardStatuses": "Manage board statuses",
"BoardName": "Board",
"MakePrivate": "Make",
"MakePrivateDescription": "",
"CardCreateLabel": "Card",
"CardPlaceholder": "Card placeholder",
"Board": "Board",
"Boards": "Boards",
"MyBoards": "My boards",
"BoardApplication": "Boards",
"Card": "Card",
"Assignee": "Assignee",
"Description": "Description",
"Location": "Location",
"Members": "Members",
"BoardCreateLabel": "Board",
"Settings": "Settings"
}
}

View File

@ -0,0 +1,28 @@
{
"string": {
"CreateBoard": "Create board",
"CreateCard": "Create card",
"CardName": "Card name",
"Cards": "Cards",
"SelectBoard": "Select board",
"More": "More...",
"Title": "Title",
"ManageBoardStatuses": "Manage board statuses",
"BoardName": "Board",
"MakePrivate": "Make",
"MakePrivateDescription": "",
"CardCreateLabel": "Create card",
"CardPlaceholder": "Card placeholder",
"Board": "Board",
"Boards": "Boards",
"MyBoards": "My boards",
"BoardApplication": "Boards",
"Card": "Card",
"Assignee": "Assignee",
"Description": "Description",
"Location": "Location",
"Members": "Members",
"BoardCreateLabel": "Board",
"Settings": "Settings"
}
}

View File

@ -0,0 +1,33 @@
{
"name": "@anticrm/board-assets",
"version": "0.6.0",
"main": "lib/index.js",
"author": "Anticrm Platform Contributors",
"license": "EPL-2.0",
"scripts": {
"build": "heft build",
"build:docs": "",
"lint": "eslint src",
"lint:fix": "eslint --fix src",
"format": "prettier --write src && eslint --fix src",
"build:watch": "tsc"
},
"devDependencies": {
"@anticrm/platform-rig": "~0.6.0",
"@types/heft-jest": "^1.0.2",
"@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": "^7.32.0",
"prettier": "^2.4.1",
"@rushstack/heft": "^0.41.1",
"@types/node": "~16.11.12"
},
"dependencies": {
"@anticrm/platform": "~0.6.5",
"@anticrm/board": "~0.6.0"
}
}

View File

@ -0,0 +1,26 @@
//
// 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 { addStringsLoader, loadMetadata } from '@anticrm/platform'
import board, { boardId } from '@anticrm/board'
const icons = require('../assets/icons.svg') as string // eslint-disable-line
loadMetadata(board.icon, {
Board: `${icons}#board`,
Card: `${icons}#card`
})
addStringsLoader(boardId, async (lang: string) => await import(`../lang/${lang}.json`))

View File

@ -0,0 +1,15 @@
{
"compilerOptions": {
"moduleResolution": "node",
"target": "esnext",
"module": "esnext",
"declaration": true,
"outDir": "./lib",
"strict": true,
"esModuleInterop": true,
"lib": [
"esnext",
"dom"
]
}
}

View 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
}
}

View File

@ -0,0 +1,50 @@
{
"name": "@anticrm/board-resources",
"version": "0.6.0",
"main": "src/index.ts",
"author": "Anticrm Platform Contributors",
"license": "EPL-2.0",
"scripts": {
"build": "echo 'no build for ui'",
"build:docs": "api-extractor run --local",
"lint": "eslint",
"lint:fix": "eslint --fix src",
"format": "prettier --write --plugin-search-dir=. src && eslint --fix src"
},
"devDependencies": {
"svelte-loader": "^3.1.2",
"sass": "^1.37.5",
"svelte-preprocess": "^4.10.3",
"@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",
"typescript": "^4.3.5"
},
"dependencies": {
"@anticrm/platform": "~0.6.5",
"svelte": "^3.37.0",
"@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/attachment-resources": "~0.6.0",
"@anticrm/contact-resources": "~0.6.0",
"@anticrm/chunter-resources": "~0.6.0",
"@anticrm/notification": "~0.6.0"
}
}

View File

@ -0,0 +1,5 @@
module.exports = {
plugins: [
require('autoprefixer')
]
}

View 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.
-->
<script lang="ts">
import type { Card } from '@anticrm/board'
import { Icon, showPanel } from '@anticrm/ui'
import view from '@anticrm/view'
import lead from '../plugin'
export let value: Card
export let inline: boolean = false
async function show () {
showPanel(view.component.EditDoc, value._id, value._class, 'full')
}
</script>
{#if value}
<a
class="flex-presenter"
class:inline-presenter={inline}
href="#{encodeURIComponent([view.component.EditDoc, value._id, value._class].join('|'))}"
on:click={show}
>
<div class="icon">
<Icon icon={lead.icon.Lead} size={'small'} />
</div>
<span class="label">{value.title}</span>
</a>
{/if}

View File

@ -0,0 +1,77 @@
<!--
// 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 core, { Ref } from '@anticrm/core'
import { getClient, SpaceCreateCard } from '@anticrm/presentation'
import { Component, EditBox, Grid, IconFolder, ToggleWithLabel } from '@anticrm/ui'
import { createEventDispatcher } from 'svelte'
import board from '../plugin'
import task, { createKanban, KanbanTemplate } from '@anticrm/task'
const dispatch = createEventDispatcher()
let name: string = ''
const description: string = ''
let templateId: Ref<KanbanTemplate> | undefined
export function canClose (): boolean {
return name === '' && templateId !== undefined
}
const client = getClient()
async function createFunnel (): 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: []
}
)
await createKanban(client, id, templateId)
}
</script>
<SpaceCreateCard
label={board.string.CreateBoard}
okAction={createFunnel}
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 />
<!-- <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
}}/>
</Grid>
</SpaceCreateCard>

View File

@ -0,0 +1,98 @@
<!--
// 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 as BoardCard } from '@anticrm/board'
import { AttachedData, generateId, Ref, SortingOrder, Space } from '@anticrm/core'
import { OK, Status } from '@anticrm/platform'
import { Card, getClient } from '@anticrm/presentation'
import task, { calcRank } from '@anticrm/task'
import { EditBox, Grid, Status as StatusControl } from '@anticrm/ui'
import { createEventDispatcher } from 'svelte'
import board from '../plugin'
export let space: Ref<Space>
let _space = space
const status: Status = OK
let title: string = ''
const dispatch = createEventDispatcher()
const client = getClient()
const cardId = generateId() as Ref<BoardCard>
export function canClose (): boolean {
return title !== ''
}
async function createCard () {
const state = await client.findOne(task.class.State, { space: _space })
if (state === undefined) {
throw new Error('create application: state not found')
}
const sequence = await client.findOne(task.class.Sequence, { attachedTo: board.class.Card })
if (sequence === undefined) {
throw new Error('sequence object not found')
}
const lastOne = await client.findOne(
board.class.Card,
{ state: state._id },
{ sort: { rank: SortingOrder.Descending } }
)
const incResult = await client.update(sequence, { $inc: { sequence: 1 } }, true)
const value: AttachedData<BoardCard> = {
state: state._id,
doneState: null,
number: (incResult as any).object.sequence,
title: title,
rank: calcRank(lastOne, undefined),
assignee: null,
description: '',
members: [],
location: ''
}
await client.addCollection(board.class.Card, _space, space, board.class.Board, 'cards', value, cardId)
dispatch('close')
}
</script>
<Card
label={board.string.CreateCard}
okAction={createCard}
canSave={title.length > 0}
spaceClass={board.class.Board}
spaceLabel={board.string.BoardName}
spacePlaceholder={board.string.SelectBoard}
bind:space={_space}
on:close={() => {
dispatch('close')
}}
>
<StatusControl slot="error" {status} />
<Grid column={1} rowGap={1.5}>
<EditBox
label={board.string.CardName}
bind:value={title}
icon={board.icon.Card}
placeholder={board.string.CardPlaceholder}
maxWidth={'16rem'}
focus
/>
</Grid>
</Card>

View File

@ -0,0 +1,49 @@
<!--
// 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 { getClient } from '@anticrm/presentation'
import { EditBox, Grid } from '@anticrm/ui'
import { createEventDispatcher, onMount } from 'svelte'
import board from '../plugin'
export let object: Card
const dispatch = createEventDispatcher()
const client = getClient()
function change (field: string, value: any) {
client.updateDoc(object._class, object.space, object._id, { [field]: value })
}
onMount(() => {
dispatch('open', { ignoreKeys: ['comments', 'number', 'title'] })
})
</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={(evt) => change('title', object.title)}
/>
</Grid>
{/if}

View File

@ -0,0 +1,85 @@
<!--
// 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 { AttachmentsPresenter } from '@anticrm/attachment-resources'
import { CommentsPresenter } from '@anticrm/chunter-resources'
import { ContactPresenter } from '@anticrm/contact-resources'
import type { WithLookup } from '@anticrm/core'
import type { Card } from '@anticrm/board'
import { ActionIcon, Component, IconMoreH, showPanel, showPopup } from '@anticrm/ui'
import view from '@anticrm/view'
import { ContextMenu } from '@anticrm/view-resources'
import board from '../plugin'
import notification from '@anticrm/notification'
export let object: WithLookup<Card>
export let draggable: boolean
function showMenu (ev?: Event): void {
showPopup(ContextMenu, { object }, (ev as MouseEvent).target as HTMLElement)
}
function showLead () {
showPanel(view.component.EditDoc, object._id, object._class, 'full')
}
</script>
<div class="card-container" {draggable} class:draggable on:dragstart on:dragend>
<div class="flex-between mb-4">
<div class="flex-col">
<div class="fs-title cursor-pointer" on:click={showLead}>{object.title}</div>
</div>
<div class="flex-row-center">
<div class="mr-2">
<Component is={notification.component.NotificationPresenter} props={{ value: object }} />
</div>
<ActionIcon
label={board.string.More}
action={(evt) => {
showMenu(evt)
}}
icon={IconMoreH}
size={'small'}
/>
</div>
</div>
<div class="flex-between">
<div class="flex-row-center">
{#if (object.attachments ?? 0) > 0}
<div class="step-lr75"><AttachmentsPresenter value={object} /></div>
{/if}
{#if (object.comments ?? 0) > 0}
<div class="step-lr75"><CommentsPresenter value={object} /></div>
{/if}
</div>
</div>
</div>
<style lang="scss">
.card-container {
display: flex;
flex-direction: column;
padding: 1rem 1.25rem;
background-color: rgba(222, 222, 240, 0.06);
border-radius: 0.75rem;
user-select: none;
backdrop-filter: blur(10px);
&.draggable {
cursor: grab;
}
}
</style>

View File

@ -0,0 +1,17 @@
<script lang="ts">
import { Icon } from '@anticrm/ui'
import board from '@anticrm/board'
</script>
<div class="flex-center template-icon">
<Icon icon={board.icon.Board} size="small" />
</div>
<style lang="scss">
.template-icon {
width: 100%;
height: 100%;
color: #fff;
background-color: #4474F6;
}
</style>

View File

@ -0,0 +1,34 @@
//
// 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 { Resources } from '@anticrm/platform'
import CardPresenter from './components/CardPresenter.svelte'
import CreateBoard from './components/CreateBoard.svelte'
import CreateCard from './components/CreateCard.svelte'
import EditCard from './components/EditCard.svelte'
import KanbanCard from './components/KanbanCard.svelte'
import TemplatesIcon from './components/TemplatesIcon.svelte'
export default async (): Promise<Resources> => ({
component: {
CreateBoard,
CreateCard,
EditCard,
KanbanCard,
CardPresenter,
TemplatesIcon
}
})

View File

@ -0,0 +1,57 @@
//
// 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.
//
import board, { boardId } from '@anticrm/board'
import { IntlString, mergeIds } from '@anticrm/platform'
import { AnyComponent } from '@anticrm/ui'
export default mergeIds(boardId, board, {
string: {
BoardName: '' as IntlString,
MakePrivate: '' as IntlString,
MakePrivateDescription: '' as IntlString,
CreateBoard: '' as IntlString,
CardName: '' as IntlString,
More: '' as IntlString,
SelectBoard: '' as IntlString,
CreateCard: '' as IntlString,
CardCreateLabel: '' as IntlString,
Customer: '' as IntlString,
Cards: '' as IntlString,
NoCardsForDocument: '' as IntlString,
CardPlaceholder: '' as IntlString,
Board: '' as IntlString,
Boards: '' as IntlString,
MyBoards: '' as IntlString,
BoardApplication: '' as IntlString,
Card: '' as IntlString,
Title: '' as IntlString,
Assignee: '' as IntlString,
ManageBoardStatuses: '' as IntlString,
Description: '' as IntlString,
Location: '' as IntlString,
Members: '' as IntlString,
BoardCreateLabel: '' as IntlString,
Settings: '' as IntlString
},
component: {
CreateCustomer: '' as AnyComponent,
CardsPresenter: '' as AnyComponent,
Boards: '' as AnyComponent,
Members: '' as AnyComponent,
Settings: '' as AnyComponent
}
})

View File

@ -0,0 +1,5 @@
const sveltePreprocess = require('svelte-preprocess')
module.exports = {
preprocess: sveltePreprocess()
};

View File

@ -0,0 +1,15 @@
{
"compilerOptions": {
"moduleResolution": "node",
"target": "esnext",
"module": "esnext",
"declaration": true,
"outDir": "./lib",
"strict": true,
"esModuleInterop": true,
"lib": [
"esnext",
"dom"
]
}
}

View File

@ -0,0 +1,7 @@
module.exports = {
extends: ['./node_modules/@anticrm/platform-rig/profiles/default/config/eslint.config.json'],
parserOptions: {
tsconfigRootDir: __dirname,
project: './tsconfig.json'
}
}

4
plugins/board/.npmignore Normal file
View File

@ -0,0 +1,4 @@
*
!/lib/**
!CHANGELOG.md
/lib/**/__tests__/

View File

@ -0,0 +1,18 @@
// The "rig.json" file directs tools to look for their config files in an external package.
// Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package
{
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
/**
* (Required) The name of the rig package to inherit from.
* It should be an NPM package name with the "-rig" suffix.
*/
"rigPackageName": "@anticrm/platform-rig"
/**
* (Optional) Selects a config profile from the rig package. The name must consist of
* lowercase alphanumeric words separated by hyphens, for example "sample-profile".
* If omitted, then the "default" profile will be used."
*/
// "rigProfile": "your-profile-name"
}

View File

@ -0,0 +1,35 @@
{
"name": "@anticrm/board",
"version": "0.6.0",
"main": "lib/index.js",
"author": "Anticrm Platform Contributors",
"license": "EPL-2.0",
"scripts": {
"build": "heft build",
"build:watch": "tsc",
"lint:fix": "eslint --fix src",
"lint": "eslint src",
"format": "prettier --write src && eslint --fix src"
},
"devDependencies": {
"@anticrm/platform-rig": "~0.6.0",
"@types/heft-jest": "^1.0.2",
"@typescript-eslint/eslint-plugin": "^5.4.0",
"eslint-plugin-import": "^2.25.3",
"eslint-plugin-promise": "^5.1.1",
"eslint-plugin-node": "^11.1.0",
"eslint": "^7.32.0",
"@typescript-eslint/parser": "^5.4.0",
"eslint-config-standard-with-typescript": "^21.0.1",
"prettier": "^2.4.1",
"@rushstack/heft": "^0.41.1",
"typescript": "^4.3.5"
},
"dependencies": {
"@anticrm/contact": "~0.6.5",
"@anticrm/core": "~0.6.16",
"@anticrm/platform": "~0.6.5",
"@anticrm/view": "~0.6.0",
"@anticrm/task": "~0.6.0"
}
}

View File

@ -0,0 +1,97 @@
//
// 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 { Employee } from '@anticrm/contact'
import type { AttachedDoc, Class, Doc, Markup, Ref } from '@anticrm/core'
import type { Asset, Plugin } from '@anticrm/platform'
import { plugin } from '@anticrm/platform'
import type { KanbanTemplateSpace, SpaceWithStates, Task } from '@anticrm/task'
/**
* @public
*/
export interface Board extends SpaceWithStates {
color?: number
background?: string
}
/**
* @public
*/
export interface BoardView extends SpaceWithStates {
title: string
type: 'table' | 'calendar'
boards: Ref<Board>[]
}
/**
* @public
*/
export interface CardLabel extends AttachedDoc {
attachedTo: Ref<Board>
title: string
color: number
}
/**
* @public
*/
export interface Card extends Task {
title: string
description: Markup
members: Ref<Employee>[]
location: string
coverColor?: number
coverImage?: string
comments?: number
attachments?: number
}
/**
* @public
*/
export const boardId = 'board' as Plugin
/**
* @public
*/
const boards = plugin(boardId, {
app: {
Board: '' as Ref<Doc>
},
class: {
Board: '' as Ref<Class<Board>>,
Card: '' as Ref<Class<Card>>
},
icon: {
Board: '' as Asset,
Card: '' as Asset
},
space: {
BoardTemplates: '' as Ref<KanbanTemplateSpace>
}
})
/**
* @public
*/
export default boards

View File

@ -0,0 +1,9 @@
{
"extends": "./node_modules/@anticrm/platform-rig/profiles/default/tsconfig.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./lib",
"lib": ["esnext", "dom"]
}
}

View File

@ -21,8 +21,8 @@
"Description": "", "Description": "",
"Status": "", "Status": "",
"Priority": "", "Priority": "",
"Number": "", "Number": "Number",
"Assignee": "", "Assignee": "Assignee",
"Parent": "", "Parent": "",
"BlockedBy": "", "BlockedBy": "",
"RelatedTo": "", "RelatedTo": "",

View File

@ -53,7 +53,6 @@
$: update(currentView?.class, currentSpace) $: update(currentView?.class, currentSpace)
</script> </script>
<SpaceHeader spaceId={space} {viewlets} {createItemDialog} {createItemLabel} bind:search={search} bind:viewlet={viewlet} /> <SpaceHeader spaceId={space} {viewlets} {createItemDialog} {createItemLabel} bind:search={search} bind:viewlet={viewlet} />
{#if _class && space} {#if _class && space}
<SpaceContent {space} {_class} {search} {viewlet} /> <SpaceContent {space} {_class} {search} {viewlet} />

View File

@ -85,7 +85,7 @@
<TreeNode label={model.label} actions={async () => [addSpace]} indent={'ml-2'}> <TreeNode label={model.label} actions={async () => [addSpace]} indent={'ml-2'}>
{#each spaces as space (space._id)} {#each spaces as space (space._id)}
{#if model.specials} {#if model.specials}
<TreeNode title={space.name} indent={'ml-2'}> <TreeNode title={space.name} indent={'ml-2'} actions={() => getActions(space)}>
{#each model.specials as special} {#each model.specials as special}
<SpecialElement <SpecialElement
indent={'ml-4'} indent={'ml-4'}

View File

@ -1237,5 +1237,26 @@
"projectFolder": "models/tracker", "projectFolder": "models/tracker",
"shouldPublish": true "shouldPublish": true
}, },
{
"packageName": "@anticrm/board",
"projectFolder": "plugins/board",
"shouldPublish": true
},
{
"packageName": "@anticrm/board-assets",
"projectFolder": "plugins/board-assets",
"shouldPublish": true
},
{
"packageName": "@anticrm/board-resources",
"projectFolder": "plugins/board-resources",
"shouldPublish": true
},
{
"packageName": "@anticrm/model-board",
"projectFolder": "models/board",
"shouldPublish": true
}
] ]
} }