mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-22 19:11:33 +03:00
parent
5f5102a939
commit
e4b7575147
@ -156,7 +156,9 @@ async function genApplicant (
|
|||||||
assignee: faker.random.arrayElement(emoloyeeIds),
|
assignee: faker.random.arrayElement(emoloyeeIds),
|
||||||
state: faker.random.arrayElement(states),
|
state: faker.random.arrayElement(states),
|
||||||
doneState: null,
|
doneState: null,
|
||||||
rank: rank as string
|
rank: rank as string,
|
||||||
|
startDate: null,
|
||||||
|
dueDate: null
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update or create candidate
|
// Update or create candidate
|
||||||
|
@ -251,7 +251,9 @@ async function createApplicant (
|
|||||||
assignee: null,
|
assignee: null,
|
||||||
state,
|
state,
|
||||||
doneState: null,
|
doneState: null,
|
||||||
rank: calcRank(lastOne, undefined)
|
rank: calcRank(lastOne, undefined),
|
||||||
|
startDate: null,
|
||||||
|
dueDate: null
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update or create candidate
|
// Update or create candidate
|
||||||
|
@ -14,9 +14,9 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
// To help typescript locate view plugin properly
|
// To help typescript locate view plugin properly
|
||||||
import type { Board, Card, CardDate, CardLabel, MenuPage, CommonBoardPreference } from '@anticrm/board'
|
import type { Board, Card, CardLabel, MenuPage, CommonBoardPreference } from '@anticrm/board'
|
||||||
import type { Employee } from '@anticrm/contact'
|
import type { Employee } from '@anticrm/contact'
|
||||||
import { DOMAIN_MODEL, IndexKind, Markup, Ref, Timestamp, Type } from '@anticrm/core'
|
import { DOMAIN_MODEL, IndexKind, Markup, Ref } from '@anticrm/core'
|
||||||
import {
|
import {
|
||||||
ArrOf,
|
ArrOf,
|
||||||
Builder,
|
Builder,
|
||||||
@ -33,7 +33,7 @@ import {
|
|||||||
import attachment from '@anticrm/model-attachment'
|
import attachment from '@anticrm/model-attachment'
|
||||||
import chunter from '@anticrm/model-chunter'
|
import chunter from '@anticrm/model-chunter'
|
||||||
import contact from '@anticrm/model-contact'
|
import contact from '@anticrm/model-contact'
|
||||||
import core, { TAttachedDoc, TDoc, TObj } from '@anticrm/model-core'
|
import core, { TAttachedDoc, TDoc } from '@anticrm/model-core'
|
||||||
import task, { TSpaceWithStates, TTask } from '@anticrm/model-task'
|
import task, { TSpaceWithStates, TTask } from '@anticrm/model-task'
|
||||||
import view, { actionTemplates, createAction } from '@anticrm/model-view'
|
import view, { actionTemplates, createAction } from '@anticrm/model-view'
|
||||||
import workbench, { Application } from '@anticrm/model-workbench'
|
import workbench, { Application } from '@anticrm/model-workbench'
|
||||||
@ -42,13 +42,6 @@ import type { AnyComponent } from '@anticrm/ui'
|
|||||||
import preference, { TPreference } from '@anticrm/model-preference'
|
import preference, { TPreference } from '@anticrm/model-preference'
|
||||||
import board from './plugin'
|
import board from './plugin'
|
||||||
|
|
||||||
/**
|
|
||||||
* @public
|
|
||||||
*/
|
|
||||||
export function TypeCardDate (): Type<CardDate> {
|
|
||||||
return { _class: board.class.CardDate, label: board.string.Dates }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Model(board.class.Board, task.class.SpaceWithStates)
|
@Model(board.class.Board, task.class.SpaceWithStates)
|
||||||
@UX(board.string.Board, board.icon.Board)
|
@UX(board.string.Board, board.icon.Board)
|
||||||
export class TBoard extends TSpaceWithStates implements Board {
|
export class TBoard extends TSpaceWithStates implements Board {
|
||||||
@ -56,14 +49,6 @@ export class TBoard extends TSpaceWithStates implements Board {
|
|||||||
background!: string
|
background!: string
|
||||||
}
|
}
|
||||||
|
|
||||||
@Model(board.class.CardDate, core.class.Obj, DOMAIN_MODEL)
|
|
||||||
@UX(board.string.Dates)
|
|
||||||
export class TCardDate extends TObj implements CardDate {
|
|
||||||
dueDate?: Timestamp
|
|
||||||
isChecked?: boolean
|
|
||||||
startDate?: Timestamp
|
|
||||||
}
|
|
||||||
|
|
||||||
@Model(board.class.CardLabel, core.class.AttachedDoc, DOMAIN_MODEL)
|
@Model(board.class.CardLabel, core.class.AttachedDoc, DOMAIN_MODEL)
|
||||||
@UX(board.string.Labels)
|
@UX(board.string.Labels)
|
||||||
export class TCardLabel extends TAttachedDoc implements CardLabel {
|
export class TCardLabel extends TAttachedDoc implements CardLabel {
|
||||||
@ -90,9 +75,6 @@ export class TCard extends TTask implements Card {
|
|||||||
@Prop(TypeBoolean(), board.string.IsArchived)
|
@Prop(TypeBoolean(), board.string.IsArchived)
|
||||||
isArchived?: boolean
|
isArchived?: boolean
|
||||||
|
|
||||||
@Prop(TypeCardDate(), board.string.Dates)
|
|
||||||
date?: CardDate
|
|
||||||
|
|
||||||
@Prop(TypeMarkup(), board.string.Description)
|
@Prop(TypeMarkup(), board.string.Description)
|
||||||
@Index(IndexKind.FullText)
|
@Index(IndexKind.FullText)
|
||||||
description!: Markup
|
description!: Markup
|
||||||
@ -125,7 +107,7 @@ export class TMenuPage extends TDoc implements MenuPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function createModel (builder: Builder): void {
|
export function createModel (builder: Builder): void {
|
||||||
builder.createModel(TBoard, TCard, TCardLabel, TCardDate, TMenuPage, TCommonBoardPreference)
|
builder.createModel(TBoard, TCard, TCardLabel, TMenuPage, TCommonBoardPreference)
|
||||||
|
|
||||||
builder.createDoc(board.class.MenuPage, core.space.Model, {
|
builder.createDoc(board.class.MenuPage, core.space.Model, {
|
||||||
component: board.component.Archive,
|
component: board.component.Archive,
|
||||||
@ -228,10 +210,6 @@ export function createModel (builder: Builder): void {
|
|||||||
presenter: board.component.CardLabelPresenter
|
presenter: board.component.CardLabelPresenter
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.mixin(board.class.CardDate, core.class.Class, view.mixin.AttributePresenter, {
|
|
||||||
presenter: board.component.CardDatePresenter
|
|
||||||
})
|
|
||||||
|
|
||||||
builder.mixin(board.class.Board, core.class.Class, view.mixin.AttributePresenter, {
|
builder.mixin(board.class.Board, core.class.Class, view.mixin.AttributePresenter, {
|
||||||
presenter: board.component.BoardPresenter
|
presenter: board.component.BoardPresenter
|
||||||
})
|
})
|
||||||
@ -269,6 +247,16 @@ export function createModel (builder: Builder): void {
|
|||||||
board.viewlet.Table
|
board.viewlet.Table
|
||||||
)
|
)
|
||||||
|
|
||||||
|
builder.createDoc(
|
||||||
|
task.class.WonState,
|
||||||
|
core.space.Model,
|
||||||
|
{
|
||||||
|
title: board.string.Completed,
|
||||||
|
rank: '0'
|
||||||
|
},
|
||||||
|
board.state.Completed
|
||||||
|
)
|
||||||
|
|
||||||
// card actions
|
// card actions
|
||||||
createAction(
|
createAction(
|
||||||
builder,
|
builder,
|
||||||
|
@ -29,7 +29,6 @@ export default mergeIds(boardId, board, {
|
|||||||
KanbanCard: '' as AnyComponent,
|
KanbanCard: '' as AnyComponent,
|
||||||
CardPresenter: '' as AnyComponent,
|
CardPresenter: '' as AnyComponent,
|
||||||
CardLabelPresenter: '' as AnyComponent,
|
CardLabelPresenter: '' as AnyComponent,
|
||||||
CardDatePresenter: '' as AnyComponent,
|
|
||||||
BoardPresenter: '' as AnyComponent,
|
BoardPresenter: '' as AnyComponent,
|
||||||
TemplatesIcon: '' as AnyComponent,
|
TemplatesIcon: '' as AnyComponent,
|
||||||
Cards: '' as AnyComponent,
|
Cards: '' as AnyComponent,
|
||||||
|
@ -113,6 +113,12 @@ export class TTask extends TAttachedDoc implements Task {
|
|||||||
// @Prop(TypeRef(contact.class.Employee), task.string.TaskAssignee)
|
// @Prop(TypeRef(contact.class.Employee), task.string.TaskAssignee)
|
||||||
assignee!: Ref<Employee> | null
|
assignee!: Ref<Employee> | null
|
||||||
|
|
||||||
|
@Prop(TypeDate(), task.string.DueDate)
|
||||||
|
dueDate!: Timestamp | null
|
||||||
|
|
||||||
|
@Prop(TypeDate(), task.string.StartDate)
|
||||||
|
startDate!: Timestamp | null
|
||||||
|
|
||||||
declare rank: string
|
declare rank: string
|
||||||
|
|
||||||
@Prop(Collection(task.class.TodoItem), task.string.Todos)
|
@Prop(Collection(task.class.TodoItem), task.string.Todos)
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
import type { Ref, Space } from '@anticrm/core'
|
import type { Ref, Space } from '@anticrm/core'
|
||||||
import { ObjectSearchCategory, ObjectSearchFactory } from '@anticrm/model-presentation'
|
import { ObjectSearchCategory, ObjectSearchFactory } from '@anticrm/model-presentation'
|
||||||
import type { IntlString, Resource } from '@anticrm/platform'
|
import type { Resource } from '@anticrm/platform'
|
||||||
import { mergeIds } from '@anticrm/platform'
|
import { mergeIds } from '@anticrm/platform'
|
||||||
import { KanbanTemplate, taskId } from '@anticrm/task'
|
import { KanbanTemplate, taskId } from '@anticrm/task'
|
||||||
import task from '@anticrm/task-resources/src/plugin'
|
import task from '@anticrm/task-resources/src/plugin'
|
||||||
@ -58,31 +58,6 @@ export default mergeIds(taskId, task, {
|
|||||||
StatusTableView: '' as AnyComponent,
|
StatusTableView: '' as AnyComponent,
|
||||||
TaskHeader: '' as AnyComponent
|
TaskHeader: '' as AnyComponent
|
||||||
},
|
},
|
||||||
string: {
|
|
||||||
TaskState: '' as IntlString,
|
|
||||||
TaskStateTitle: '' as IntlString,
|
|
||||||
TaskStateDone: '' as IntlString,
|
|
||||||
TaskNumber: '' as IntlString,
|
|
||||||
Todo: '' as IntlString,
|
|
||||||
TaskDone: '' as IntlString,
|
|
||||||
TaskDueTo: '' as IntlString,
|
|
||||||
TaskParent: '' as IntlString,
|
|
||||||
IssueName: '' as IntlString,
|
|
||||||
TaskComments: '' as IntlString,
|
|
||||||
TaskLabels: '' as IntlString,
|
|
||||||
StateTemplateTitle: '' as IntlString,
|
|
||||||
StateTemplateColor: '' as IntlString,
|
|
||||||
KanbanTemplateTitle: '' as IntlString,
|
|
||||||
Rank: '' as IntlString,
|
|
||||||
EditStates: '' as IntlString,
|
|
||||||
MarkAsDone: '' as IntlString,
|
|
||||||
MarkAsUndone: '' as IntlString,
|
|
||||||
Kanban: '' as IntlString,
|
|
||||||
ApplicationLabelTask: '' as IntlString,
|
|
||||||
Projects: '' as IntlString,
|
|
||||||
SearchTask: '' as IntlString,
|
|
||||||
ManageProjectStatues: '' as IntlString
|
|
||||||
},
|
|
||||||
space: {
|
space: {
|
||||||
TasksPublic: '' as Ref<Space>
|
TasksPublic: '' as Ref<Space>
|
||||||
},
|
},
|
||||||
|
@ -451,6 +451,7 @@ input.search {
|
|||||||
.w-9 { width: 2.25rem; }
|
.w-9 { width: 2.25rem; }
|
||||||
.w-14 { width: 3.5rem; }
|
.w-14 { width: 3.5rem; }
|
||||||
.w-16 { width: 4rem; }
|
.w-16 { width: 4rem; }
|
||||||
|
.w-22 { width: 5.5rem; }
|
||||||
.w-24 { width: 6rem; }
|
.w-24 { width: 6rem; }
|
||||||
.w-60 { width: 15rem; }
|
.w-60 { width: 15rem; }
|
||||||
.w-85 { width: 21.25rem; }
|
.w-85 { width: 21.25rem; }
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
"Minutes": "{minutes, plural, =0 {less than a minute ago} =1 {a minute ago} other {# minutes ago}}",
|
"Minutes": "{minutes, plural, =0 {less than a minute ago} =1 {a minute ago} other {# minutes ago}}",
|
||||||
"Hours": "{hours, plural, =0 {less than an hour ago} =1 {an hour ago} other {# hours ago}}",
|
"Hours": "{hours, plural, =0 {less than an hour ago} =1 {an hour ago} other {# hours ago}}",
|
||||||
"Days": "{days, plural, =0 {today} =1 {yesterday} other {# days ago}}",
|
"Days": "{days, plural, =0 {today} =1 {yesterday} other {# days ago}}",
|
||||||
"Months": "{months, plural, =0 {this month} =1 {a month aago} other {# months ago}}",
|
"Months": "{months, plural, =0 {this month} =1 {a month ago} other {# months ago}}",
|
||||||
"Years": "{years, plural, =0 {this year} =1 {a year ago} other {# years ago}}",
|
"Years": "{years, plural, =0 {this year} =1 {a year ago} other {# years ago}}",
|
||||||
"ShowMore": "Show more",
|
"ShowMore": "Show more",
|
||||||
"ShowLess": "Show less",
|
"ShowLess": "Show less",
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"string": {
|
"string": {
|
||||||
|
"Completed": "Completed",
|
||||||
"Name": "Name",
|
"Name": "Name",
|
||||||
"CreateBoard": "Create board",
|
"CreateBoard": "Create board",
|
||||||
"OpenCard": "Open Card",
|
"OpenCard": "Open Card",
|
||||||
@ -28,17 +29,14 @@
|
|||||||
"IsArchived": "Archived",
|
"IsArchived": "Archived",
|
||||||
"BoardCreateLabel": "Board",
|
"BoardCreateLabel": "Board",
|
||||||
"Settings": "Settings",
|
"Settings": "Settings",
|
||||||
"InList": "in list",
|
|
||||||
"Suggested": "Suggested",
|
"Suggested": "Suggested",
|
||||||
"AddToCard": "Add to card",
|
|
||||||
"Labels": "Labels",
|
"Labels": "Labels",
|
||||||
"CreateLabel": "Create a new label",
|
"CreateLabel": "Create a new label",
|
||||||
"SearchLabels": "Search labels...",
|
"SearchLabels": "Search labels...",
|
||||||
"SelectColor": "Select a color",
|
"SelectColor": "Select a color",
|
||||||
"NoColor": "No color.",
|
"NoColor": "No color.",
|
||||||
"NoColorInfo": "This won't show up on the front of cards.",
|
"NoColorInfo": "This won't show up on the front of cards.",
|
||||||
"Checklist": "Checklist",
|
"Checklists": "Checklists",
|
||||||
"AddChecklistItem": "Add an item",
|
|
||||||
"ChecklistDropdownNone": "(none)",
|
"ChecklistDropdownNone": "(none)",
|
||||||
"ShowDoneChecklistItems": "Show checked items ({done})",
|
"ShowDoneChecklistItems": "Show checked items ({done})",
|
||||||
"HideDoneChecklistItems": "Hide checked items",
|
"HideDoneChecklistItems": "Hide checked items",
|
||||||
@ -80,8 +78,6 @@
|
|||||||
"List": "List",
|
"List": "List",
|
||||||
"Position": "Position",
|
"Position": "Position",
|
||||||
"Current": "{label} (current)",
|
"Current": "{label} (current)",
|
||||||
"StartDate": "Start date",
|
|
||||||
"DueDate": "Due date",
|
|
||||||
"Save": "Save",
|
"Save": "Save",
|
||||||
"Remove": "Remove",
|
"Remove": "Remove",
|
||||||
"NullDate": "M/D/YYYY",
|
"NullDate": "M/D/YYYY",
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"string": {
|
"string": {
|
||||||
|
"Completed": "Завершено",
|
||||||
"Name": "Название",
|
"Name": "Название",
|
||||||
"CreateBoard": "Создать",
|
"CreateBoard": "Создать",
|
||||||
"OpenCard": "Открыть",
|
"OpenCard": "Открыть",
|
||||||
@ -28,17 +29,14 @@
|
|||||||
"IsArchived": "Архивировано",
|
"IsArchived": "Архивировано",
|
||||||
"BoardCreateLabel": "Board",
|
"BoardCreateLabel": "Board",
|
||||||
"Settings": "Настройки",
|
"Settings": "Настройки",
|
||||||
"InList": "в списке",
|
|
||||||
"Suggested": "Предложенное",
|
"Suggested": "Предложенное",
|
||||||
"AddToCard": "Добавить",
|
|
||||||
"Labels": "Метки",
|
"Labels": "Метки",
|
||||||
"CreateLabel": "Создать",
|
"CreateLabel": "Создать",
|
||||||
"SearchLabels": "Поиск...",
|
"SearchLabels": "Поиск...",
|
||||||
"SelectColor": "Выберите цвет",
|
"SelectColor": "Выберите цвет",
|
||||||
"NoColor": "Без цвета.",
|
"NoColor": "Без цвета.",
|
||||||
"NoColorInfo": "Не будет показываться на доске.",
|
"NoColorInfo": "Не будет показываться на доске.",
|
||||||
"Checklist": "Списки",
|
"Checklists": "Списки",
|
||||||
"AddChecklistItem": "Добавить",
|
|
||||||
"ChecklistDropdownNone": "(не выбрано)",
|
"ChecklistDropdownNone": "(не выбрано)",
|
||||||
"ShowDoneChecklistItems": "Показать отмеченные ({done})",
|
"ShowDoneChecklistItems": "Показать отмеченные ({done})",
|
||||||
"HideDoneChecklistItems": "Скрыть отмеченные",
|
"HideDoneChecklistItems": "Скрыть отмеченные",
|
||||||
@ -80,8 +78,6 @@
|
|||||||
"List": "Список",
|
"List": "Список",
|
||||||
"Position": "Позиция",
|
"Position": "Позиция",
|
||||||
"Current": "{label} (текущий)",
|
"Current": "{label} (текущий)",
|
||||||
"StartDate": "Начало",
|
|
||||||
"DueDate": "Срок",
|
|
||||||
"Save": "Сохранить",
|
"Save": "Сохранить",
|
||||||
"Remove": "Удалить",
|
"Remove": "Удалить",
|
||||||
"NullDate": "М/Д/ГГГГ",
|
"NullDate": "М/Д/ГГГГ",
|
||||||
|
@ -66,7 +66,9 @@
|
|||||||
description: '',
|
description: '',
|
||||||
members: [],
|
members: [],
|
||||||
labels: [],
|
labels: [],
|
||||||
location: ''
|
location: '',
|
||||||
|
startDate: null,
|
||||||
|
dueDate: null
|
||||||
}
|
}
|
||||||
|
|
||||||
await client.addCollection(board.class.Card, _space, space, board.class.Board, 'cards', value, cardId)
|
await client.addCollection(board.class.Card, _space, space, board.class.Board, 'cards', value, cardId)
|
||||||
|
@ -14,23 +14,24 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { Attachments } from '@anticrm/attachment-resources'
|
||||||
import type { Card } from '@anticrm/board'
|
import type { Card } from '@anticrm/board'
|
||||||
import { Class, Ref } from '@anticrm/core'
|
import core, { Class, Ref, Space } from '@anticrm/core'
|
||||||
import { Panel } from '@anticrm/panel'
|
import { Panel } from '@anticrm/panel'
|
||||||
import { createQuery, getClient } from '@anticrm/presentation'
|
import { createQuery, getClient } from '@anticrm/presentation'
|
||||||
import type { State, TodoItem } from '@anticrm/task'
|
import type { State, TodoItem } from '@anticrm/task'
|
||||||
import task from '@anticrm/task'
|
import task from '@anticrm/task'
|
||||||
import { StyledTextBox } from '@anticrm/text-editor'
|
import { StyledTextBox } from '@anticrm/text-editor'
|
||||||
import { Button, EditBox, Icon, Label } from '@anticrm/ui'
|
import { Button, CircleButton, EditBox, IconAdd, IconMoreH, Label, showPopup } from '@anticrm/ui'
|
||||||
import { invokeAction, UpDownNavigator } from '@anticrm/view-resources'
|
import { ContextMenu, invokeAction, UpDownNavigator } from '@anticrm/view-resources'
|
||||||
import { createEventDispatcher, onMount } from 'svelte'
|
import { createEventDispatcher, onMount } from 'svelte'
|
||||||
import board from '../plugin'
|
import board from '../plugin'
|
||||||
import { getCardActions } from '../utils/CardActionUtils'
|
import { getCardActions } from '../utils/CardActionUtils'
|
||||||
import { updateCard } from '../utils/CardUtils'
|
import { updateCard } from '../utils/CardUtils'
|
||||||
|
import { getPopupAlignment } from '../utils/PopupUtils'
|
||||||
import CardActions from './editor/CardActions.svelte'
|
import CardActions from './editor/CardActions.svelte'
|
||||||
import CardAttachments from './editor/CardAttachments.svelte'
|
|
||||||
import CardChecklist from './editor/CardChecklist.svelte'
|
import CardChecklist from './editor/CardChecklist.svelte'
|
||||||
import CardDetails from './editor/CardDetails.svelte'
|
import AddChecklist from './popups/AddChecklist.svelte'
|
||||||
|
|
||||||
export let _id: Ref<Card>
|
export let _id: Ref<Card>
|
||||||
export let _class: Ref<Class<Card>>
|
export let _class: Ref<Class<Card>>
|
||||||
@ -38,10 +39,12 @@
|
|||||||
const client = getClient()
|
const client = getClient()
|
||||||
const cardQuery = createQuery()
|
const cardQuery = createQuery()
|
||||||
const stateQuery = createQuery()
|
const stateQuery = createQuery()
|
||||||
|
const spaceQuery = createQuery()
|
||||||
const checklistsQuery = createQuery()
|
const checklistsQuery = createQuery()
|
||||||
|
|
||||||
let object: Card | undefined
|
let object: Card | undefined
|
||||||
let state: State | undefined
|
let state: State | undefined
|
||||||
|
let space: Space | undefined
|
||||||
let handleMove: (e: Event) => void
|
let handleMove: (e: Event) => void
|
||||||
let checklists: TodoItem[] = []
|
let checklists: TodoItem[] = []
|
||||||
|
|
||||||
@ -51,6 +54,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addChecklist (e: Event) {
|
||||||
|
showPopup(AddChecklist, { value: object }, getPopupAlignment(e))
|
||||||
|
}
|
||||||
|
|
||||||
$: cardQuery.query(_class, { _id }, (result) => {
|
$: cardQuery.query(_class, { _id }, (result) => {
|
||||||
object = result[0]
|
object = result[0]
|
||||||
})
|
})
|
||||||
@ -60,6 +67,11 @@
|
|||||||
state = result[0]
|
state = result[0]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
$: object?.space &&
|
||||||
|
spaceQuery.query(core.class.Space, { _id: object.space }, (result) => {
|
||||||
|
space = result[0]
|
||||||
|
})
|
||||||
|
|
||||||
$: object &&
|
$: object &&
|
||||||
checklistsQuery.query(task.class.TodoItem, { space: object.space, attachedTo: object._id }, (result) => {
|
checklistsQuery.query(task.class.TodoItem, { space: object.space, attachedTo: object._id }, (result) => {
|
||||||
checklists = result
|
checklists = result
|
||||||
@ -86,8 +98,9 @@
|
|||||||
icon={board.icon.Card}
|
icon={board.icon.Card}
|
||||||
title={object?.title}
|
title={object?.title}
|
||||||
{object}
|
{object}
|
||||||
isHeader={false}
|
isHeader
|
||||||
isAside={true}
|
isAside={true}
|
||||||
|
isSub={false}
|
||||||
isFullSize
|
isFullSize
|
||||||
on:fullsize
|
on:fullsize
|
||||||
on:close={() => dispatch('close')}
|
on:close={() => dispatch('close')}
|
||||||
@ -95,40 +108,33 @@
|
|||||||
<svelte:fragment slot="navigator">
|
<svelte:fragment slot="navigator">
|
||||||
<UpDownNavigator element={object} />
|
<UpDownNavigator element={object} />
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
|
<svelte:fragment slot="header">
|
||||||
<!-- TODO cover -->
|
<div class="flex fs-title flex-gap-1">
|
||||||
<div class="flex-row-stretch">
|
<span class="over-underline" on:click={handleMove}>{space?.name}</span>><span
|
||||||
<div class="w-9">
|
class="over-underline"
|
||||||
<Icon icon={board.icon.Card} size="large" />
|
on:click={handleMove}>{state?.title}</span
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="fs-title text-lg">
|
</svelte:fragment>
|
||||||
|
<svelte:fragment slot="tools">
|
||||||
|
<Button
|
||||||
|
icon={IconMoreH}
|
||||||
|
kind="transparent"
|
||||||
|
size="medium"
|
||||||
|
on:click={(e) => {
|
||||||
|
showPopup(ContextMenu, { object }, getPopupAlignment(e))
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</svelte:fragment>
|
||||||
|
<div class="flex-row-stretch">
|
||||||
|
<div class="fs-title text-xl">
|
||||||
<EditBox bind:value={object.title} maxWidth="39rem" focus on:change={() => change('title', object?.title)} />
|
<EditBox bind:value={object.title} maxWidth="39rem" focus on:change={() => change('title', object?.title)} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-row-stretch">
|
|
||||||
<div class="w-9" />
|
|
||||||
<div>
|
|
||||||
<Label label={board.string.InList} />
|
|
||||||
<span class="state-name ml-1" on:click={handleMove}>{state?.title}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex-row-stretch">
|
<div class="flex-row-stretch">
|
||||||
<div class="flex-grow mr-4">
|
<div class="flex-grow mr-4">
|
||||||
<div class="flex-row-stretch">
|
<div class="flex-row-stretch">
|
||||||
<div class="w-9" />
|
<div class="background-bg-accent border-bg-accent border-radius-3 p-2 mt-2 w-full">
|
||||||
<CardDetails bind:value={object} />
|
|
||||||
</div>
|
|
||||||
<div class="flex-row-stretch mt-4 mb-2">
|
|
||||||
<div class="w-9">
|
|
||||||
<Icon icon={board.icon.Card} size="large" />
|
|
||||||
</div>
|
|
||||||
<div class="fs-title">
|
|
||||||
<Label label={board.string.Description} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex-row-stretch">
|
|
||||||
<div class="w-9" />
|
|
||||||
<div class="background-bg-accent border-bg-accent border-radius-3 p-2 w-full">
|
|
||||||
<StyledTextBox
|
<StyledTextBox
|
||||||
alwaysEdit={true}
|
alwaysEdit={true}
|
||||||
showButtons={false}
|
showButtons={false}
|
||||||
@ -138,13 +144,22 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<CardAttachments value={object} />
|
<div class="mt-6">
|
||||||
{#each checklists as checklist}
|
<Attachments objectId={_id} {_class} space={object.space} attachments={object.attachments ?? 0} />
|
||||||
<CardChecklist value={checklist} />
|
</div>
|
||||||
{/each}
|
<div class="flex-row-center mt-6">
|
||||||
|
<span class="text-xl font-medium caption-color mr-3"><Label label={board.string.Checklists} /></span>
|
||||||
|
<CircleButton icon={IconAdd} size="small" selected on:click={addChecklist} />
|
||||||
|
</div>
|
||||||
|
<div class="mr-2 ml-2 mb-4">
|
||||||
|
{#each checklists as checklist}
|
||||||
|
<CardChecklist value={checklist} />
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<span slot="actions-label"><Label label={board.string.Card} /></span>
|
||||||
|
<span slot="actions" />
|
||||||
<svelte:fragment slot="custom-attributes" let:direction>
|
<svelte:fragment slot="custom-attributes" let:direction>
|
||||||
{#if direction === 'column'}
|
{#if direction === 'column'}
|
||||||
<CardActions bind:value={object} />
|
<CardActions bind:value={object} />
|
||||||
@ -154,13 +169,3 @@
|
|||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
</Panel>
|
</Panel>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.state-name {
|
|
||||||
text-decoration: underline;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: var(--caption-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { AttachmentDroppable, AttachmentsPresenter } from '@anticrm/attachment-resources'
|
import { AttachmentDroppable, AttachmentsPresenter } from '@anticrm/attachment-resources'
|
||||||
import type { Card, CardDate } from '@anticrm/board'
|
import type { Card } from '@anticrm/board'
|
||||||
import { CommentsPresenter } from '@anticrm/chunter-resources'
|
import { CommentsPresenter } from '@anticrm/chunter-resources'
|
||||||
import contact, { Employee } from '@anticrm/contact'
|
import contact, { Employee } from '@anticrm/contact'
|
||||||
import type { Ref, WithLookup } from '@anticrm/core'
|
import type { Ref, WithLookup } from '@anticrm/core'
|
||||||
@ -62,9 +62,6 @@
|
|||||||
updateCardMembers(object, client, e.detail)
|
updateCardMembers(object, client, e.detail)
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateDate (e: CustomEvent<CardDate>) {
|
|
||||||
client.update(object, { date: e.detail })
|
|
||||||
}
|
|
||||||
$: coverBackground = object.cover?.color ? `background-color: ${numberToHexColor(object.cover.color)}` : ''
|
$: coverBackground = object.cover?.color ? `background-color: ${numberToHexColor(object.cover.color)}` : ''
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -178,9 +175,9 @@
|
|||||||
<div class="float-left">
|
<div class="float-left">
|
||||||
<NotificationPresenter {object} />
|
<NotificationPresenter {object} />
|
||||||
</div>
|
</div>
|
||||||
{#if object.date && hasDate(object)}
|
{#if hasDate(object)}
|
||||||
<div class="float-left">
|
<div class="float-left">
|
||||||
<DatePresenter value={object.date} size="x-small" on:update={updateDate} />
|
<DatePresenter value={object} size="x-small" />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if object.description}
|
{#if object.description}
|
||||||
|
@ -24,7 +24,8 @@
|
|||||||
'title',
|
'title',
|
||||||
'$lookup.state',
|
'$lookup.state',
|
||||||
{ key: '', presenter: board.component.CardLabels, label: board.string.Labels },
|
{ key: '', presenter: board.component.CardLabels, label: board.string.Labels },
|
||||||
'date',
|
'startDate',
|
||||||
|
'dueDate',
|
||||||
{ key: 'members', presenter: board.component.UserBoxList, label: board.string.Members, sortingKey: '' },
|
{ key: 'members', presenter: board.component.UserBoxList, label: board.string.Members, sortingKey: '' },
|
||||||
'modifiedOn'
|
'modifiedOn'
|
||||||
]}
|
]}
|
||||||
|
@ -8,4 +8,4 @@
|
|||||||
export let value: Ref<Employee>[]
|
export let value: Ref<Employee>[]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<UserBoxList items={value} _class={contact.class.Employee} label={board.string.Members} />
|
<UserBoxList items={value} _class={contact.class.Employee} label={board.string.Members} on:update />
|
||||||
|
@ -53,7 +53,9 @@
|
|||||||
description: '',
|
description: '',
|
||||||
members: [],
|
members: [],
|
||||||
labels: [],
|
labels: [],
|
||||||
location: ''
|
location: '',
|
||||||
|
startDate: null,
|
||||||
|
dueDate: null
|
||||||
}
|
}
|
||||||
|
|
||||||
return client.addCollection(board.class.Card, space, space, board.class.Board, 'cards', value, newCardId)
|
return client.addCollection(board.class.Card, space, space, board.class.Board, 'cards', value, newCardId)
|
||||||
|
@ -15,78 +15,101 @@
|
|||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Card } from '@anticrm/board'
|
import type { Card } from '@anticrm/board'
|
||||||
|
import board from '@anticrm/board'
|
||||||
|
import { Employee } from '@anticrm/contact'
|
||||||
|
import { Ref } from '@anticrm/core'
|
||||||
import { getClient } from '@anticrm/presentation'
|
import { getClient } from '@anticrm/presentation'
|
||||||
import { Button, IconAttachment, Label, showPopup } from '@anticrm/ui'
|
import ui, { Button, CheckBox, DateRangePresenter, Label, IconAdd } from '@anticrm/ui'
|
||||||
import type { Action } from '@anticrm/view'
|
import { invokeAction } from '@anticrm/view-resources'
|
||||||
import { getActions, invokeAction } from '@anticrm/view-resources'
|
|
||||||
import AddChecklist from '../popups/AddChecklist.svelte'
|
|
||||||
import AttachmentPicker from '../popups/AttachmentPicker.svelte'
|
|
||||||
import plugin from '../../plugin'
|
import plugin from '../../plugin'
|
||||||
import { getPopupAlignment } from '../../utils/PopupUtils'
|
import { getCardActions } from '../../utils/CardActionUtils'
|
||||||
|
import { updateCardMembers } from '../../utils/CardUtils'
|
||||||
|
import ColorPresenter from '../presenters/ColorPresenter.svelte'
|
||||||
|
import UserBoxList from '../UserBoxList.svelte'
|
||||||
|
import CardLabels from './CardLabels.svelte'
|
||||||
|
|
||||||
export let value: Card
|
export let value: Card
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
|
|
||||||
let topActions: Action[] = []
|
let coverHandler: (e: Event) => void
|
||||||
let toolsActions: Action[] = []
|
|
||||||
async function fetch () {
|
function updateMembers (e: CustomEvent<Ref<Employee>[]>) {
|
||||||
const result = await getActions(client, value, value._class)
|
updateCardMembers(value, client, e.detail)
|
||||||
topActions = result.filter((action) => action.context.group === 'top')
|
|
||||||
toolsActions = result.filter((action) => action.context.group !== 'top')
|
|
||||||
}
|
}
|
||||||
fetch()
|
function updateState (e: CustomEvent<boolean>) {
|
||||||
$: value.members && fetch()
|
if (e.detail) {
|
||||||
$: value.isArchived && fetch()
|
client.update(value, { doneState: board.state.Completed })
|
||||||
$: !value.isArchived && fetch()
|
} else {
|
||||||
|
client.update(value, { doneState: null })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getCardActions(client, {
|
||||||
|
_id: { $in: [board.action.Cover] }
|
||||||
|
}).then(async (result) => {
|
||||||
|
for (const action of result) {
|
||||||
|
if (action._id === board.action.Cover) {
|
||||||
|
coverHandler = (e: Event) => invokeAction(value, e, action.action, action.actionProps)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if value}
|
{#if value}
|
||||||
<div class="flex-col flex-gap-3">
|
<div class="flex-col flex-gap-3 mt-4">
|
||||||
<div class="flex-col flex-gap-1">
|
<div class="flex-row-stretch flex-gap-1 items-center">
|
||||||
<Label label={plugin.string.AddToCard} />
|
<div class="label w-24">
|
||||||
{#each topActions as action}
|
<Label label={plugin.string.Completed} />
|
||||||
<Button
|
</div>
|
||||||
icon={action.icon}
|
<CheckBox checked={value.doneState === board.state.Completed} on:value={updateState} />
|
||||||
label={action.label}
|
</div>
|
||||||
kind="no-border"
|
<div class="flex-row-stretch flex-gap-1 items-center">
|
||||||
justify="left"
|
<div class="label w-24">
|
||||||
on:click={(e) => {
|
<Label label={plugin.string.Members} />
|
||||||
invokeAction(value, e, action.action, action.actionProps)
|
</div>
|
||||||
}}
|
<UserBoxList value={value.members ?? []} on:update={updateMembers} />
|
||||||
/>
|
</div>
|
||||||
{/each}
|
<div class="flex-row-stretch flex-gap-1 items-center">
|
||||||
<Button
|
<div class="label w-24">
|
||||||
icon={plugin.icon.Card}
|
<Label label={plugin.string.Labels} />
|
||||||
label={plugin.string.Checklist}
|
</div>
|
||||||
kind="no-border"
|
<CardLabels {value} />
|
||||||
justify="left"
|
</div>
|
||||||
on:click={(e) => {
|
<div class="flex-row-stretch flex-gap-1 items-center">
|
||||||
showPopup(AddChecklist, { value }, getPopupAlignment(e))
|
<div class="label w-24">
|
||||||
}}
|
<Label label={ui.string.StartDate} />
|
||||||
/>
|
</div>
|
||||||
<Button
|
<DateRangePresenter
|
||||||
icon={IconAttachment}
|
value={value.startDate}
|
||||||
label={plugin.string.Attachments}
|
editable={true}
|
||||||
kind="no-border"
|
withTime={false}
|
||||||
justify="left"
|
on:change={(e) => {
|
||||||
on:click={(e) => {
|
console.log(e)
|
||||||
showPopup(AttachmentPicker, { value }, getPopupAlignment(e))
|
client.update(value, { startDate: e.detail })
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-col flex-gap-1">
|
<div class="flex-row-stretch flex-gap-1 items-center">
|
||||||
<Label label={plugin.string.Actions} />
|
<div class="label w-24">
|
||||||
{#each toolsActions as action}
|
<Label label={ui.string.DueDate} />
|
||||||
<Button
|
</div>
|
||||||
icon={action.icon}
|
<DateRangePresenter
|
||||||
label={action.label}
|
value={value.dueDate}
|
||||||
kind="no-border"
|
editable={true}
|
||||||
justify="left"
|
withTime={false}
|
||||||
on:click={(e) => {
|
on:change={(e) => client.update(value, { dueDate: e.detail })}
|
||||||
invokeAction(value, e, action.action, action.actionProps)
|
/>
|
||||||
}}
|
</div>
|
||||||
/>
|
<div class="flex-row-stretch flex-gap-1 items-center">
|
||||||
{/each}
|
<div class="label w-24">
|
||||||
|
<Label label={plugin.string.Cover} />
|
||||||
|
</div>
|
||||||
|
{#if !value.cover?.color}
|
||||||
|
<Button icon={IconAdd} kind="no-border" on:click={coverHandler} />
|
||||||
|
{:else}
|
||||||
|
<ColorPresenter value={value.cover.color} on:click={coverHandler} />
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -1,63 +0,0 @@
|
|||||||
<!--
|
|
||||||
// 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 attachment, { Attachment } from '@anticrm/attachment'
|
|
||||||
import type { Card } from '@anticrm/board'
|
|
||||||
import { getClient } from '@anticrm/presentation'
|
|
||||||
import { Button, Icon, IconAttachment, Label, showPopup } from '@anticrm/ui'
|
|
||||||
import AttachmentPicker from '../popups/AttachmentPicker.svelte'
|
|
||||||
import AttachmentPresenter from '../presenters/AttachmentPresenter.svelte'
|
|
||||||
import board from '../../plugin'
|
|
||||||
import { getPopupAlignment } from '../../utils/PopupUtils'
|
|
||||||
|
|
||||||
export let value: Card
|
|
||||||
const client = getClient()
|
|
||||||
let attachments: Attachment[] = []
|
|
||||||
|
|
||||||
async function fetch () {
|
|
||||||
attachments = await client.findAll(attachment.class.Attachment, { space: value.space, attachedTo: value._id })
|
|
||||||
}
|
|
||||||
|
|
||||||
function addAttachment (e: Event) {
|
|
||||||
showPopup(AttachmentPicker, { object: value }, getPopupAlignment(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
$: value?.attachments && value.attachments > 0 && fetch()
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{#if value !== undefined && value.attachments !== undefined && value.attachments > 0}
|
|
||||||
<div class="flex-col w-full">
|
|
||||||
<div class="flex-row-stretch mt-4 mb-2">
|
|
||||||
<div class="w-9">
|
|
||||||
<Icon icon={IconAttachment} size="large" />
|
|
||||||
</div>
|
|
||||||
<div class="flex-grow fs-title">
|
|
||||||
<Label label={board.string.Attachments} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex-row-stretch">
|
|
||||||
<div class="w-9" />
|
|
||||||
<div class="flex-col flex-gap-1 w-full">
|
|
||||||
{#each attachments as attach}
|
|
||||||
<AttachmentPresenter value={attach} />
|
|
||||||
{/each}
|
|
||||||
<div class="mt-2">
|
|
||||||
<Button label={board.string.AddAttachment} kind="no-border" on:click={addAttachment} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
@ -21,7 +21,8 @@
|
|||||||
Button,
|
Button,
|
||||||
CheckBox,
|
CheckBox,
|
||||||
TextAreaEditor,
|
TextAreaEditor,
|
||||||
Icon,
|
IconAdd,
|
||||||
|
IconDelete,
|
||||||
IconMoreH,
|
IconMoreH,
|
||||||
Progress,
|
Progress,
|
||||||
showPopup,
|
showPopup,
|
||||||
@ -131,9 +132,6 @@
|
|||||||
{#if value !== undefined}
|
{#if value !== undefined}
|
||||||
<div class="flex-col w-full">
|
<div class="flex-col w-full">
|
||||||
<div class="flex-row-stretch mt-4 mb-2">
|
<div class="flex-row-stretch mt-4 mb-2">
|
||||||
<div class="w-9">
|
|
||||||
<Icon icon={board.icon.Card} size="large" />
|
|
||||||
</div>
|
|
||||||
{#if isEditingName}
|
{#if isEditingName}
|
||||||
<div class="flex-grow">
|
<div class="flex-grow">
|
||||||
<TextAreaEditor
|
<TextAreaEditor
|
||||||
@ -154,19 +152,18 @@
|
|||||||
{value.name}
|
{value.name}
|
||||||
</div>
|
</div>
|
||||||
{#if done > 0}
|
{#if done > 0}
|
||||||
<div class="mr-1">
|
<Button
|
||||||
<Button
|
label={hideDoneItems ? board.string.ShowDoneChecklistItems : board.string.HideDoneChecklistItems}
|
||||||
label={hideDoneItems ? board.string.ShowDoneChecklistItems : board.string.HideDoneChecklistItems}
|
labelParams={{ done }}
|
||||||
labelParams={{ done }}
|
kind="transparent"
|
||||||
kind="no-border"
|
size="small"
|
||||||
size="small"
|
on:click={() => {
|
||||||
on:click={() => {
|
hideDoneItems = !hideDoneItems
|
||||||
hideDoneItems = !hideDoneItems
|
}}
|
||||||
}}
|
/>
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{/if}
|
{/if}
|
||||||
<Button label={board.string.Delete} kind="no-border" size="small" on:click={deleteChecklist} />
|
<Button icon={IconAdd} kind="transparent" size="small" on:click={startAddingItem} />
|
||||||
|
<Button icon={IconDelete} kind="transparent" size="small" on:click={deleteChecklist} />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-row-stretch mb-2 mt-1">
|
<div class="flex-row-stretch mb-2 mt-1">
|
||||||
@ -254,8 +251,6 @@
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
|
||||||
<Button label={board.string.AddChecklistItem} kind="no-border" size="small" on:click={startAddingItem} />
|
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,122 +0,0 @@
|
|||||||
<!--
|
|
||||||
// Copyright © 2022 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, CardDate } from '@anticrm/board'
|
|
||||||
|
|
||||||
import contact, { Employee } from '@anticrm/contact'
|
|
||||||
import { Ref } from '@anticrm/core'
|
|
||||||
import { createQuery, getClient, UsersPopup } from '@anticrm/presentation'
|
|
||||||
import { Button, IconAdd, Label, showPopup } from '@anticrm/ui'
|
|
||||||
import { invokeAction } from '@anticrm/view-resources'
|
|
||||||
|
|
||||||
import board from '../../plugin'
|
|
||||||
import { getCardActions } from '../../utils/CardActionUtils'
|
|
||||||
import { hasDate, updateCardMembers } from '../../utils/CardUtils'
|
|
||||||
import { getPopupAlignment } from '../../utils/PopupUtils'
|
|
||||||
import DatePresenter from '../presenters/DatePresenter.svelte'
|
|
||||||
import MemberPresenter from '../presenters/MemberPresenter.svelte'
|
|
||||||
import CardLabels from './CardLabels.svelte'
|
|
||||||
|
|
||||||
export let value: Card
|
|
||||||
const query = createQuery()
|
|
||||||
const client = getClient()
|
|
||||||
let members: Employee[] = []
|
|
||||||
const membersHandler = (e?: Event) => {
|
|
||||||
showPopup(
|
|
||||||
UsersPopup,
|
|
||||||
{
|
|
||||||
_class: contact.class.Employee,
|
|
||||||
multiSelect: true,
|
|
||||||
allowDeselect: true,
|
|
||||||
selectedUsers: members?.map((m) => m._id) ?? [],
|
|
||||||
placeholder: board.string.SearchMembers
|
|
||||||
},
|
|
||||||
getPopupAlignment(e),
|
|
||||||
undefined,
|
|
||||||
(result: Array<Ref<Employee>>) => {
|
|
||||||
updateCardMembers(value, client, result)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
let dateHandler: (e: Event) => void
|
|
||||||
|
|
||||||
$: membersIds = members?.map((m) => m._id) ?? []
|
|
||||||
|
|
||||||
const getMenuItems = (member: Employee) => {
|
|
||||||
return [
|
|
||||||
[
|
|
||||||
{
|
|
||||||
title: board.string.RemoveFromCard,
|
|
||||||
handler: () => {
|
|
||||||
const newMembers = membersIds.filter((m) => m !== member._id)
|
|
||||||
updateCardMembers(value, client, newMembers)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
$: query.query(contact.class.Employee, { _id: { $in: value.members } }, (result) => {
|
|
||||||
members = result
|
|
||||||
})
|
|
||||||
|
|
||||||
function updateDate (e: CustomEvent<CardDate>) {
|
|
||||||
client.update(value, { date: e.detail })
|
|
||||||
}
|
|
||||||
|
|
||||||
getCardActions(client, {
|
|
||||||
_id: { $in: [board.action.Dates] }
|
|
||||||
}).then(async (result) => {
|
|
||||||
for (const action of result) {
|
|
||||||
if (action._id === board.action.Dates) {
|
|
||||||
dateHandler = (e: Event) => invokeAction(value, e, action.action, action.actionProps)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{#if value}
|
|
||||||
{#if members && members.length > 0}
|
|
||||||
<div class="flex-col mt-4 mr-6">
|
|
||||||
<div class="text-md font-medium">
|
|
||||||
<Label label={board.string.Members} />
|
|
||||||
</div>
|
|
||||||
<div class="flex-row-center flex-gap-1">
|
|
||||||
{#each members as member}
|
|
||||||
<MemberPresenter value={member} size="large" menuItems={getMenuItems(member)} />
|
|
||||||
{/each}
|
|
||||||
<Button icon={IconAdd} shape="circle" kind="no-border" size="large" on:click={membersHandler} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
{#if value.labels && value.labels.length > 0}
|
|
||||||
<div class="flex-col mt-4 mr-6">
|
|
||||||
<div class="text-md font-medium">
|
|
||||||
<Label label={board.string.Labels} />
|
|
||||||
</div>
|
|
||||||
<CardLabels {value} />
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
{#if value.date && hasDate(value)}
|
|
||||||
<div class="flex-col mt-4">
|
|
||||||
<div class="text-md font-medium">
|
|
||||||
<Label label={board.string.Dates} />
|
|
||||||
</div>
|
|
||||||
{#key value.date}
|
|
||||||
<DatePresenter value={value.date} on:click={dateHandler} on:update={updateDate} />
|
|
||||||
{/key}
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
{/if}
|
|
@ -68,7 +68,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if labels && labels.length > 0}
|
{#if labels}
|
||||||
<div
|
<div
|
||||||
class="flex-row-center flex-wrap flex-gap-1 mb-1"
|
class="flex-row-center flex-wrap flex-gap-1 mb-1"
|
||||||
class:labels-inline-container={isInline}
|
class:labels-inline-container={isInline}
|
||||||
|
@ -106,7 +106,7 @@
|
|||||||
<div class="antiPopup w-85">
|
<div class="antiPopup w-85">
|
||||||
<div class="relative flex-row-center w-full ">
|
<div class="relative flex-row-center w-full ">
|
||||||
<div class="flex-center flex-grow fs-title mt-1 mb-1">
|
<div class="flex-center flex-grow fs-title mt-1 mb-1">
|
||||||
<Label label={board.string.Checklist} />
|
<Label label={board.string.Checklists} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="absolute mr-1 mt-1 mb-1" style:top="0" style:right="0">
|
<div class="absolute mr-1 mt-1 mb-1" style:top="0" style:right="0">
|
||||||
|
@ -52,7 +52,9 @@
|
|||||||
description: '',
|
description: '',
|
||||||
members: [],
|
members: [],
|
||||||
location: '',
|
location: '',
|
||||||
labels: labels ?? []
|
labels: labels ?? [],
|
||||||
|
startDate: value.startDate,
|
||||||
|
dueDate: value.dueDate
|
||||||
}
|
}
|
||||||
|
|
||||||
await client.addCollection(
|
await client.addCollection(
|
||||||
|
@ -1,35 +1,37 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from 'svelte'
|
import { Card } from '@anticrm/board'
|
||||||
import { Label, Button, DateRangePresenter, CheckBox, Component } from '@anticrm/ui'
|
|
||||||
import { Card, CardDate } from '@anticrm/board'
|
|
||||||
import calendar from '@anticrm/calendar'
|
import calendar from '@anticrm/calendar'
|
||||||
|
import { DocumentUpdate } from '@anticrm/core'
|
||||||
|
import { createQuery, getClient } from '@anticrm/presentation'
|
||||||
|
import task from '@anticrm/task'
|
||||||
|
import { Label, Button, DateRangePresenter, Component } from '@anticrm/ui'
|
||||||
|
import { createEventDispatcher } from 'svelte'
|
||||||
|
|
||||||
import board from '../../plugin'
|
import board from '../../plugin'
|
||||||
import { getClient } from '@anticrm/presentation'
|
|
||||||
|
|
||||||
export let value: Card
|
export let value: Card
|
||||||
|
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
|
const query = createQuery()
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
let startDate = value.date?.startDate
|
let startDate = value.startDate
|
||||||
let savedStartDate = value.date?.startDate ?? Date.now()
|
let dueDate = value.dueDate
|
||||||
let startDateEnabled = startDate !== undefined
|
|
||||||
$: startDate && (savedStartDate = startDate)
|
|
||||||
let dueDate = value.date?.dueDate
|
|
||||||
let savedDueDate = value.date?.dueDate ?? Date.now()
|
|
||||||
let dueDateEnabled = dueDate !== undefined
|
|
||||||
$: dueDate && (savedDueDate = dueDate)
|
|
||||||
|
|
||||||
function getEmptyDate (): CardDate {
|
|
||||||
return { _class: value.date?._class ?? board.class.CardDate }
|
|
||||||
}
|
|
||||||
|
|
||||||
function update () {
|
function update () {
|
||||||
const date: CardDate = getEmptyDate()
|
const date: DocumentUpdate<Card> = {}
|
||||||
if (startDate !== undefined) date.startDate = startDate
|
if (startDate !== undefined) date.startDate = startDate
|
||||||
if (dueDate !== undefined) date.dueDate = dueDate
|
if (dueDate !== undefined) date.dueDate = dueDate
|
||||||
client.update(value, { date })
|
client.update(value, date)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$: value?._id &&
|
||||||
|
query.query(board.class.Card, { _id: value._id }, (result) => {
|
||||||
|
if (result?.[0]) {
|
||||||
|
startDate = result[0].startDate
|
||||||
|
dueDate = result[0].dueDate
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="antiPopup antiPopup-withHeader antiPopup-withTitle antiPopup-withCategory w-85">
|
<div class="antiPopup antiPopup-withHeader antiPopup-withTitle antiPopup-withCategory w-85">
|
||||||
@ -39,35 +41,19 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="ap-space bottom-divider" />
|
<div class="ap-space bottom-divider" />
|
||||||
<div class="ap-category">
|
<div class="ap-category">
|
||||||
<div class="categoryItem flex-center whitespace-nowrap">
|
<div class="categoryItem flex-center whitespace-nowrap w-22">
|
||||||
<Label label={board.string.StartDate} />
|
<Label label={task.string.StartDate} />
|
||||||
</div>
|
|
||||||
<div class="categoryItem p-2 flex-center">
|
|
||||||
<CheckBox
|
|
||||||
bind:checked={startDateEnabled}
|
|
||||||
on:value={() => {
|
|
||||||
startDate = startDateEnabled ? savedStartDate : undefined
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="categoryItem w-full p-2">
|
<div class="categoryItem w-full p-2">
|
||||||
<DateRangePresenter bind:value={startDate} editable={startDateEnabled} labelNull={board.string.NullDate} />
|
<DateRangePresenter bind:value={startDate} editable={true} labelNull={board.string.NullDate} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ap-category">
|
<div class="ap-category">
|
||||||
<div class="categoryItem flex-center whitespace-nowrap">
|
<div class="categoryItem flex-center whitespace-nowrap w-22">
|
||||||
<Label label={board.string.DueDate} />
|
<Label label={task.string.DueDate} />
|
||||||
</div>
|
|
||||||
<div class="categoryItem p-2 flex-center">
|
|
||||||
<CheckBox
|
|
||||||
bind:checked={dueDateEnabled}
|
|
||||||
on:value={() => {
|
|
||||||
dueDate = dueDateEnabled ? savedDueDate : undefined
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="categoryItem w-full p-2">
|
<div class="categoryItem w-full p-2">
|
||||||
<DateRangePresenter bind:value={dueDate} editable={dueDateEnabled} labelNull={board.string.NullDate} />
|
<DateRangePresenter bind:value={dueDate} editable={true} labelNull={board.string.NullDate} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ap-footer">
|
<div class="ap-footer">
|
||||||
@ -81,9 +67,10 @@
|
|||||||
<Button
|
<Button
|
||||||
label={board.string.Remove}
|
label={board.string.Remove}
|
||||||
size={'small'}
|
size={'small'}
|
||||||
on:click={() => {
|
on:click={async () => {
|
||||||
client.update(value, { date: getEmptyDate() })
|
await client.update(value, { startDate: null, dueDate: null })
|
||||||
dispatch('close')
|
startDate = null
|
||||||
|
dueDate = null
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
|
@ -1,50 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import { createEventDispatcher } from 'svelte'
|
|
||||||
import { Label, Button, ActionIcon, IconClose, EditBox } from '@anticrm/ui'
|
|
||||||
import board from '../../plugin'
|
|
||||||
import { getClient } from '@anticrm/presentation'
|
|
||||||
import { Attachment } from '@anticrm/attachment'
|
|
||||||
|
|
||||||
export let object: Attachment
|
|
||||||
|
|
||||||
let { name } = object
|
|
||||||
|
|
||||||
const client = getClient()
|
|
||||||
const dispatch = createEventDispatcher()
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="antiPopup antiPopup-withHeader antiPopup-withCategory w-85">
|
|
||||||
<div class="ap-space" />
|
|
||||||
<div class="flex-row-center header">
|
|
||||||
<div class="flex-center flex-grow">
|
|
||||||
<Label label={board.string.Edit} />
|
|
||||||
</div>
|
|
||||||
<div class="close-icon mr-1">
|
|
||||||
<ActionIcon
|
|
||||||
icon={IconClose}
|
|
||||||
size={'small'}
|
|
||||||
action={() => {
|
|
||||||
dispatch('close')
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="ap-space bottom-divider" />
|
|
||||||
<div class="ap-category">
|
|
||||||
<div class="ap-categoryItem">
|
|
||||||
<EditBox bind:value={name} maxWidth="18rem" label={board.string.LinkName} placeholder={board.string.LinkName} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="ap-footer">
|
|
||||||
<Button
|
|
||||||
size={'small'}
|
|
||||||
label={board.string.Update}
|
|
||||||
kind={'primary'}
|
|
||||||
on:click={() => {
|
|
||||||
if (!name) return
|
|
||||||
client.update(object, { name })
|
|
||||||
dispatch('close')
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@ -1,46 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import type { Employee } from '@anticrm/contact'
|
|
||||||
import type { IntlString } from '@anticrm/platform'
|
|
||||||
import { ActionIcon, IconClose, Label } from '@anticrm/ui'
|
|
||||||
import { ContactPresenter } from '@anticrm/contact-resources'
|
|
||||||
|
|
||||||
export let member: Employee
|
|
||||||
export let menuItems: { title: IntlString; handler: () => void }[][]
|
|
||||||
export let onClose: () => void
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="antiPopup container w-85">
|
|
||||||
<div class="absolute pt-3 pr-3" style:top="0" style:right="0">
|
|
||||||
<ActionIcon icon={IconClose} size={'small'} action={onClose} />
|
|
||||||
</div>
|
|
||||||
<div class="flex p-3">
|
|
||||||
<ContactPresenter value={member} />
|
|
||||||
</div>
|
|
||||||
{#if menuItems && menuItems.length > 0}
|
|
||||||
{#each menuItems as menuSubgroup, i}
|
|
||||||
{#each menuSubgroup as menuItem}
|
|
||||||
<div
|
|
||||||
class="menu-item pr-3 pl-3 pt-2 pb-2"
|
|
||||||
on:click={() => {
|
|
||||||
menuItem.handler()
|
|
||||||
onClose()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Label label={menuItem.title} />
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
{#if i + 1 < menuItems.length}
|
|
||||||
<div class="bottom-divider ml-3 mr-3 mt-2 mb-2" />
|
|
||||||
{/if}
|
|
||||||
{/each}
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.menu-item {
|
|
||||||
&:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
background-color: var(--popup-bg-hover);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,46 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import { createEventDispatcher } from 'svelte'
|
|
||||||
import { Label, Button, ActionIcon, IconClose } from '@anticrm/ui'
|
|
||||||
import board from '../../plugin'
|
|
||||||
import { getClient } from '@anticrm/presentation'
|
|
||||||
import { Attachment } from '@anticrm/attachment'
|
|
||||||
|
|
||||||
export let object: Attachment
|
|
||||||
|
|
||||||
const client = getClient()
|
|
||||||
const dispatch = createEventDispatcher()
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="antiPopup antiPopup-withHeader antiPopup-withTitle antiPopup-withCategory w-85">
|
|
||||||
<div class="ap-space" />
|
|
||||||
<div class="flex-row-center header">
|
|
||||||
<div class="flex-center flex-grow">
|
|
||||||
<Label label={board.string.Delete} />
|
|
||||||
</div>
|
|
||||||
<div class="close-icon mr-1">
|
|
||||||
<ActionIcon
|
|
||||||
icon={IconClose}
|
|
||||||
size={'small'}
|
|
||||||
action={() => {
|
|
||||||
dispatch('close')
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="ap-space bottom-divider" />
|
|
||||||
<div class="ap-box ml-4 mr-4 mt-4">
|
|
||||||
<Label label={board.string.DeleteAttachment} />
|
|
||||||
</div>
|
|
||||||
<div class="ap-footer">
|
|
||||||
<Button
|
|
||||||
size={'small'}
|
|
||||||
width="100%"
|
|
||||||
label={board.string.Delete}
|
|
||||||
kind={'dangerous'}
|
|
||||||
on:click={() => {
|
|
||||||
client.remove(object)
|
|
||||||
dispatch('close')
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@ -1,109 +0,0 @@
|
|||||||
<!--
|
|
||||||
// Copyright © 2022 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 { Attachment } from '@anticrm/attachment'
|
|
||||||
import { PDFViewer, getFileUrl } from '@anticrm/presentation'
|
|
||||||
import { Button, showPopup, TimeSince, closeTooltip } from '@anticrm/ui'
|
|
||||||
import board from '../../plugin'
|
|
||||||
import { getPopupAlignment } from '../../utils/PopupUtils'
|
|
||||||
import EditAttachment from '../popups/EditAttachment.svelte'
|
|
||||||
import RemoveAttachment from '../popups/RemoveAttachment.svelte'
|
|
||||||
|
|
||||||
export let value: Attachment
|
|
||||||
|
|
||||||
const maxLenght: number = 30
|
|
||||||
const trimFilename = (fname: string): string =>
|
|
||||||
fname.length > maxLenght
|
|
||||||
? fname.substring(0, (maxLenght - 1) / 2) + '...' + fname.substring(-(maxLenght - 1) / 2)
|
|
||||||
: fname
|
|
||||||
|
|
||||||
function iconLabel (name: string): string {
|
|
||||||
const parts = name.split('.')
|
|
||||||
const ext = parts[parts.length - 1]
|
|
||||||
return ext.substring(0, 4).toUpperCase()
|
|
||||||
}
|
|
||||||
|
|
||||||
function openEmbedded (contentType: string) {
|
|
||||||
return contentType.includes('application/pdf') || contentType.startsWith('image/')
|
|
||||||
}
|
|
||||||
|
|
||||||
function showPreview (contentType: string) {
|
|
||||||
return contentType.startsWith('image/')
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleClick () {
|
|
||||||
closeTooltip()
|
|
||||||
showPopup(PDFViewer, { file: value.file, name: value.name, contentType: value.type }, 'float')
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="flex-row-center">
|
|
||||||
{#if openEmbedded(value.type)}
|
|
||||||
<div class="flex-center cursor-pointer icon" on:click={handleClick}>
|
|
||||||
{#if showPreview(value.type)}
|
|
||||||
<img src={getFileUrl(value.file)} alt={value.name} />
|
|
||||||
{:else}
|
|
||||||
{iconLabel(value.name)}
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
{:else}
|
|
||||||
<a class="no-line" href={getFileUrl(value.file)} download={value.name}>
|
|
||||||
<div class="flex-center icon">
|
|
||||||
{iconLabel(value.name)}
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
{/if}
|
|
||||||
<div class="flex-col-centre info">
|
|
||||||
<div class="fs-title">{trimFilename(value.name)}</div>
|
|
||||||
<div class="flex-row-center flex-gap-1">
|
|
||||||
<TimeSince value={value.lastModified} />
|
|
||||||
<Button
|
|
||||||
label={board.string.Edit}
|
|
||||||
on:click={(e) => {
|
|
||||||
showPopup(EditAttachment, { object: value }, getPopupAlignment(e))
|
|
||||||
}}
|
|
||||||
kind="transparent"
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
label={board.string.Delete}
|
|
||||||
on:click={(e) => {
|
|
||||||
showPopup(RemoveAttachment, { object: value }, getPopupAlignment(e))
|
|
||||||
}}
|
|
||||||
kind="transparent"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.icon {
|
|
||||||
flex-shrink: 0;
|
|
||||||
margin-right: 1rem;
|
|
||||||
width: 8rem;
|
|
||||||
height: 6rem;
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 1rem;
|
|
||||||
color: var(--primary-button-color);
|
|
||||||
background-color: var(--grayscale-grey-03);
|
|
||||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
|
||||||
border-radius: 0.5rem;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
img {
|
|
||||||
max-width: 8rem;
|
|
||||||
max-height: 6rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,26 +1,15 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { CardDate } from '@anticrm/board'
|
import type { Card } from '@anticrm/board'
|
||||||
import { CheckBox, DatePresenter } from '@anticrm/ui'
|
import { DatePresenter } from '@anticrm/ui'
|
||||||
import { createEventDispatcher } from 'svelte'
|
|
||||||
|
|
||||||
export let value: CardDate
|
export let value: Card
|
||||||
export let size: 'x-small' | 'small' = 'small'
|
export let size: 'x-small' | 'small' = 'small'
|
||||||
|
|
||||||
let isChecked = value?.isChecked
|
|
||||||
const dispatch = createEventDispatcher()
|
|
||||||
const isOverdue = !!value?.dueDate && new Date().getTime() > value.dueDate
|
const isOverdue = !!value?.dueDate && new Date().getTime() > value.dueDate
|
||||||
|
|
||||||
function check () {
|
|
||||||
if (isChecked === undefined || !value) return
|
|
||||||
dispatch('update', { ...value, isChecked })
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if value}
|
{#if value}
|
||||||
<div class="flex-presenter flex-gap-1 h-full">
|
<div class="flex-presenter flex-gap-1 h-full">
|
||||||
{#if value.dueDate}
|
|
||||||
<CheckBox bind:checked={isChecked} on:value={check} />
|
|
||||||
{/if}
|
|
||||||
<div class="flex-center h-full" on:click>
|
<div class="flex-center h-full" on:click>
|
||||||
<div class="flex-row-center background-button-bg-color pr-1 pl-1 border-radius-1 w-full">
|
<div class="flex-row-center background-button-bg-color pr-1 pl-1 border-radius-1 w-full">
|
||||||
{#if value.startDate}
|
{#if value.startDate}
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import { Employee, formatName } from '@anticrm/contact'
|
|
||||||
import { getFirstName, getLastName } from '@anticrm/contact'
|
|
||||||
import { Button, showPopup } from '@anticrm/ui'
|
|
||||||
import type { IntlString } from '@anticrm/platform'
|
|
||||||
import EditMember from '../popups/EditMember.svelte'
|
|
||||||
import { getPopupAlignment } from '../../utils/PopupUtils'
|
|
||||||
|
|
||||||
export let value: Employee
|
|
||||||
export let size: 'large' | 'medium'
|
|
||||||
export let menuItems: { title: IntlString; handler: () => void }[][]
|
|
||||||
|
|
||||||
const openPopup = (e: Event) => {
|
|
||||||
const onClose = () => closePopup()
|
|
||||||
|
|
||||||
const closePopup = showPopup(EditMember, { member: value, menuItems, onClose }, getPopupAlignment(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
$: firstName = getFirstName(value.name)
|
|
||||||
$: lastName = getLastName(value.name)
|
|
||||||
$: nameLabel = `${firstName?.[0] ?? ''}${lastName?.[0] ?? ''}`.toUpperCase()
|
|
||||||
$: formattedName = formatName(value.name)
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{#if value}
|
|
||||||
<Button {size} kind="no-border" shape="circle" title={formattedName} on:click={openPopup}>
|
|
||||||
<div slot="content" class="text-md">{nameLabel}</div>
|
|
||||||
</Button>
|
|
||||||
{/if}
|
|
@ -16,7 +16,6 @@
|
|||||||
import { Resources } from '@anticrm/platform'
|
import { Resources } from '@anticrm/platform'
|
||||||
import { TodoItem } from '@anticrm/task'
|
import { TodoItem } from '@anticrm/task'
|
||||||
import { getClient } from '@anticrm/presentation'
|
import { getClient } from '@anticrm/presentation'
|
||||||
import board from '@anticrm/board'
|
|
||||||
|
|
||||||
import BoardPresenter from './components/BoardPresenter.svelte'
|
import BoardPresenter from './components/BoardPresenter.svelte'
|
||||||
import CardPresenter from './components/CardPresenter.svelte'
|
import CardPresenter from './components/CardPresenter.svelte'
|
||||||
@ -29,7 +28,6 @@ import CardLabelsPopup from './components/popups/CardLabelsPopup.svelte'
|
|||||||
import MoveCard from './components/popups/MoveCard.svelte'
|
import MoveCard from './components/popups/MoveCard.svelte'
|
||||||
import CopyCard from './components/popups/CopyCard.svelte'
|
import CopyCard from './components/popups/CopyCard.svelte'
|
||||||
import DateRangePicker from './components/popups/DateRangePicker.svelte'
|
import DateRangePicker from './components/popups/DateRangePicker.svelte'
|
||||||
import CardDatePresenter from './components/presenters/DatePresenter.svelte'
|
|
||||||
import CardLabelPresenter from './components/presenters/LabelPresenter.svelte'
|
import CardLabelPresenter from './components/presenters/LabelPresenter.svelte'
|
||||||
import TemplatesIcon from './components/TemplatesIcon.svelte'
|
import TemplatesIcon from './components/TemplatesIcon.svelte'
|
||||||
import BoardHeader from './components/BoardHeader.svelte'
|
import BoardHeader from './components/BoardHeader.svelte'
|
||||||
@ -46,15 +44,12 @@ async function ConvertToCard (object: TodoItem): Promise<void> {
|
|||||||
const client = getClient()
|
const client = getClient()
|
||||||
const todoItemCard = await getCardFromTodoItem(client, object)
|
const todoItemCard = await getCardFromTodoItem(client, object)
|
||||||
if (todoItemCard === undefined) return
|
if (todoItemCard === undefined) return
|
||||||
const date =
|
|
||||||
object.dueTo === null
|
|
||||||
? {}
|
|
||||||
: { date: { _class: board.class.CardDate, dueDate: object.dueTo, isChecked: object.done } }
|
|
||||||
await createCard(client, todoItemCard.space, todoItemCard.state, {
|
await createCard(client, todoItemCard.space, todoItemCard.state, {
|
||||||
title: object.name,
|
title: object.name,
|
||||||
assignee: object.assignee,
|
assignee: object.assignee,
|
||||||
...date
|
dueDate: object.dueTo
|
||||||
})
|
})
|
||||||
|
|
||||||
await client.remove(object)
|
await client.remove(object)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +60,6 @@ export default async (): Promise<Resources> => ({
|
|||||||
EditCard,
|
EditCard,
|
||||||
KanbanCard,
|
KanbanCard,
|
||||||
CardPresenter,
|
CardPresenter,
|
||||||
CardDatePresenter,
|
|
||||||
CardLabelPresenter,
|
CardLabelPresenter,
|
||||||
TemplatesIcon,
|
TemplatesIcon,
|
||||||
KanbanView,
|
KanbanView,
|
||||||
|
@ -19,6 +19,7 @@ import type { AnyComponent } from '@anticrm/ui'
|
|||||||
|
|
||||||
export default mergeIds(boardId, board, {
|
export default mergeIds(boardId, board, {
|
||||||
string: {
|
string: {
|
||||||
|
Completed: '' as IntlString,
|
||||||
Name: '' as IntlString,
|
Name: '' as IntlString,
|
||||||
BoardName: '' as IntlString,
|
BoardName: '' as IntlString,
|
||||||
MakePrivate: '' as IntlString,
|
MakePrivate: '' as IntlString,
|
||||||
@ -49,17 +50,14 @@ export default mergeIds(boardId, board, {
|
|||||||
IsArchived: '' as IntlString,
|
IsArchived: '' as IntlString,
|
||||||
BoardCreateLabel: '' as IntlString,
|
BoardCreateLabel: '' as IntlString,
|
||||||
Settings: '' as IntlString,
|
Settings: '' as IntlString,
|
||||||
InList: '' as IntlString,
|
|
||||||
Suggested: '' as IntlString,
|
Suggested: '' as IntlString,
|
||||||
AddToCard: '' as IntlString,
|
|
||||||
Labels: '' as IntlString,
|
Labels: '' as IntlString,
|
||||||
CreateLabel: '' as IntlString,
|
CreateLabel: '' as IntlString,
|
||||||
SearchLabels: '' as IntlString,
|
SearchLabels: '' as IntlString,
|
||||||
SelectColor: '' as IntlString,
|
SelectColor: '' as IntlString,
|
||||||
NoColor: '' as IntlString,
|
NoColor: '' as IntlString,
|
||||||
NoColorInfo: '' as IntlString,
|
NoColorInfo: '' as IntlString,
|
||||||
Checklist: '' as IntlString,
|
Checklists: '' as IntlString,
|
||||||
AddChecklistItem: '' as IntlString,
|
|
||||||
ChecklistDropdownNone: '' as IntlString,
|
ChecklistDropdownNone: '' as IntlString,
|
||||||
ShowDoneChecklistItems: '' as IntlString,
|
ShowDoneChecklistItems: '' as IntlString,
|
||||||
HideDoneChecklistItems: '' as IntlString,
|
HideDoneChecklistItems: '' as IntlString,
|
||||||
@ -101,8 +99,6 @@ export default mergeIds(boardId, board, {
|
|||||||
List: '' as IntlString,
|
List: '' as IntlString,
|
||||||
Position: '' as IntlString,
|
Position: '' as IntlString,
|
||||||
Current: '' as IntlString,
|
Current: '' as IntlString,
|
||||||
StartDate: '' as IntlString,
|
|
||||||
DueDate: '' as IntlString,
|
|
||||||
Save: '' as IntlString,
|
Save: '' as IntlString,
|
||||||
Remove: '' as IntlString,
|
Remove: '' as IntlString,
|
||||||
NullDate: '' as IntlString,
|
NullDate: '' as IntlString,
|
||||||
|
@ -31,6 +31,8 @@ export async function createCard (
|
|||||||
title: '',
|
title: '',
|
||||||
state,
|
state,
|
||||||
doneState: null,
|
doneState: null,
|
||||||
|
startDate: null,
|
||||||
|
dueDate: null,
|
||||||
number: (incResult as any).object.sequence,
|
number: (incResult as any).object.sequence,
|
||||||
rank: calcRank(lastOne, undefined),
|
rank: calcRank(lastOne, undefined),
|
||||||
assignee: null,
|
assignee: null,
|
||||||
@ -95,7 +97,7 @@ export function hasCover (card: Card): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function hasDate (card: Card): boolean {
|
export function hasDate (card: Card): boolean {
|
||||||
return card.date !== undefined && (card.date.dueDate !== undefined || card.date.startDate !== undefined)
|
return card.dueDate !== undefined || card.startDate !== undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addCurrentUser (card: Card, client: Client): Promise<TxResult> | undefined {
|
export function addCurrentUser (card: Card, client: Client): Promise<TxResult> | undefined {
|
||||||
|
@ -15,11 +15,11 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import { Employee } from '@anticrm/contact'
|
import { Employee } from '@anticrm/contact'
|
||||||
import type { AttachedDoc, Class, Doc, Markup, Ref, Timestamp, Obj } from '@anticrm/core'
|
import type { AttachedDoc, Class, Doc, Markup, Ref } from '@anticrm/core'
|
||||||
import type { Asset, IntlString, Plugin } from '@anticrm/platform'
|
import type { Asset, IntlString, Plugin } from '@anticrm/platform'
|
||||||
import { plugin } from '@anticrm/platform'
|
import { plugin } from '@anticrm/platform'
|
||||||
import type { Preference } from '@anticrm/preference'
|
import type { Preference } from '@anticrm/preference'
|
||||||
import type { KanbanTemplateSpace, SpaceWithStates, Task } from '@anticrm/task'
|
import type { DoneState, KanbanTemplateSpace, SpaceWithStates, Task } from '@anticrm/task'
|
||||||
import type { AnyComponent } from '@anticrm/ui'
|
import type { AnyComponent } from '@anticrm/ui'
|
||||||
import { Action, ActionCategory } from '@anticrm/view'
|
import { Action, ActionCategory } from '@anticrm/view'
|
||||||
|
|
||||||
@ -49,15 +49,6 @@ export interface CardLabel extends AttachedDoc {
|
|||||||
isHidden?: boolean
|
isHidden?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @public
|
|
||||||
*/
|
|
||||||
export interface CardDate extends Obj {
|
|
||||||
dueDate?: Timestamp
|
|
||||||
isChecked?: boolean
|
|
||||||
startDate?: Timestamp
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
@ -72,8 +63,6 @@ export interface CardCover {
|
|||||||
*/
|
*/
|
||||||
export interface Card extends Task {
|
export interface Card extends Task {
|
||||||
title: string
|
title: string
|
||||||
|
|
||||||
date?: CardDate
|
|
||||||
description: Markup
|
description: Markup
|
||||||
|
|
||||||
isArchived?: boolean
|
isArchived?: boolean
|
||||||
@ -120,7 +109,6 @@ const boards = plugin(boardId, {
|
|||||||
class: {
|
class: {
|
||||||
Board: '' as Ref<Class<Board>>,
|
Board: '' as Ref<Class<Board>>,
|
||||||
Card: '' as Ref<Class<Card>>,
|
Card: '' as Ref<Class<Card>>,
|
||||||
CardDate: '' as Ref<Class<CardDate>>,
|
|
||||||
CardLabel: '' as Ref<Class<CardLabel>>,
|
CardLabel: '' as Ref<Class<CardLabel>>,
|
||||||
MenuPage: '' as Ref<Class<MenuPage>>,
|
MenuPage: '' as Ref<Class<MenuPage>>,
|
||||||
CommonBoardPreference: '' as Ref<Class<CommonBoardPreference>>
|
CommonBoardPreference: '' as Ref<Class<CommonBoardPreference>>
|
||||||
@ -128,6 +116,9 @@ const boards = plugin(boardId, {
|
|||||||
category: {
|
category: {
|
||||||
Card: '' as Ref<ActionCategory>
|
Card: '' as Ref<ActionCategory>
|
||||||
},
|
},
|
||||||
|
state: {
|
||||||
|
Completed: '' as Ref<DoneState>
|
||||||
|
},
|
||||||
action: {
|
action: {
|
||||||
Cover: '' as Ref<Action>,
|
Cover: '' as Ref<Action>,
|
||||||
Dates: '' as Ref<Action>,
|
Dates: '' as Ref<Action>,
|
||||||
|
@ -64,7 +64,9 @@
|
|||||||
number: (incResult as any).object.sequence,
|
number: (incResult as any).object.sequence,
|
||||||
title: title,
|
title: title,
|
||||||
rank: calcRank(lastOne, undefined),
|
rank: calcRank(lastOne, undefined),
|
||||||
assignee: null
|
assignee: null,
|
||||||
|
startDate: null,
|
||||||
|
dueDate: null
|
||||||
}
|
}
|
||||||
|
|
||||||
const customerInstance = await client.findOne(contact.class.Contact, { _id: customer! })
|
const customerInstance = await client.findOne(contact.class.Contact, { _id: customer! })
|
||||||
|
@ -56,7 +56,9 @@
|
|||||||
_id: generateId(),
|
_id: generateId(),
|
||||||
collection: 'applications',
|
collection: 'applications',
|
||||||
modifiedOn: Date.now(),
|
modifiedOn: Date.now(),
|
||||||
modifiedBy: '' as Ref<Account>
|
modifiedBy: '' as Ref<Account>,
|
||||||
|
startDate: null,
|
||||||
|
dueDate: null
|
||||||
}
|
}
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
@ -109,7 +111,9 @@
|
|||||||
doneState: null,
|
doneState: null,
|
||||||
number: (incResult as any).object.sequence,
|
number: (incResult as any).object.sequence,
|
||||||
assignee: doc.assignee,
|
assignee: doc.assignee,
|
||||||
rank: calcRank(lastOne, undefined)
|
rank: calcRank(lastOne, undefined),
|
||||||
|
startDate: null,
|
||||||
|
dueDate: null
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -128,7 +132,9 @@
|
|||||||
_id: generateId(),
|
_id: generateId(),
|
||||||
collection: 'applications',
|
collection: 'applications',
|
||||||
modifiedOn: Date.now(),
|
modifiedOn: Date.now(),
|
||||||
modifiedBy: '' as Ref<Account>
|
modifiedBy: '' as Ref<Account>,
|
||||||
|
startDate: null,
|
||||||
|
dueDate: null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
{
|
{
|
||||||
"string": {
|
"string": {
|
||||||
|
"StartDate": "Start date",
|
||||||
|
"DueDate": "Due date",
|
||||||
"TaskState": "State",
|
"TaskState": "State",
|
||||||
"TaskStateTitle": "Title",
|
"TaskStateTitle": "Title",
|
||||||
"TaskStateDone": "Done",
|
"TaskStateDone": "Done",
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
{
|
{
|
||||||
"string": {
|
"string": {
|
||||||
|
"StartDate": "Начало",
|
||||||
|
"DueDate": "Срок",
|
||||||
"TaskState": "Статус",
|
"TaskState": "Статус",
|
||||||
"TaskStateTitle": "Заголовок",
|
"TaskStateTitle": "Заголовок",
|
||||||
"TaskStateDone": "Завершен",
|
"TaskStateDone": "Завершен",
|
||||||
|
@ -81,7 +81,8 @@ export interface Task extends AttachedDoc, DocWithRank {
|
|||||||
doneState: Ref<DoneState> | null
|
doneState: Ref<DoneState> | null
|
||||||
number: number
|
number: number
|
||||||
assignee: Ref<Employee> | null
|
assignee: Ref<Employee> | null
|
||||||
|
dueDate: Timestamp | null
|
||||||
|
startDate: Timestamp | null
|
||||||
todoItems?: number
|
todoItems?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,6 +197,34 @@ const task = plugin(taskId, {
|
|||||||
interface: {
|
interface: {
|
||||||
DocWithRank: '' as Ref<Interface<DocWithRank>>
|
DocWithRank: '' as Ref<Interface<DocWithRank>>
|
||||||
},
|
},
|
||||||
|
string: {
|
||||||
|
StartDate: '' as IntlString,
|
||||||
|
DueDate: '' as IntlString,
|
||||||
|
TaskState: '' as IntlString,
|
||||||
|
TaskStateTitle: '' as IntlString,
|
||||||
|
TaskStateDone: '' as IntlString,
|
||||||
|
TaskNumber: '' as IntlString,
|
||||||
|
Todo: '' as IntlString,
|
||||||
|
TaskDone: '' as IntlString,
|
||||||
|
TaskDueTo: '' as IntlString,
|
||||||
|
TaskParent: '' as IntlString,
|
||||||
|
IssueName: '' as IntlString,
|
||||||
|
TaskComments: '' as IntlString,
|
||||||
|
TaskLabels: '' as IntlString,
|
||||||
|
StateTemplateTitle: '' as IntlString,
|
||||||
|
StateTemplateColor: '' as IntlString,
|
||||||
|
KanbanTemplateTitle: '' as IntlString,
|
||||||
|
Rank: '' as IntlString,
|
||||||
|
EditStates: '' as IntlString,
|
||||||
|
MarkAsDone: '' as IntlString,
|
||||||
|
MarkAsUndone: '' as IntlString,
|
||||||
|
Kanban: '' as IntlString,
|
||||||
|
ApplicationLabelTask: '' as IntlString,
|
||||||
|
Projects: '' as IntlString,
|
||||||
|
SearchTask: '' as IntlString,
|
||||||
|
ManageProjectStatues: '' as IntlString,
|
||||||
|
TodoItems: '' as IntlString
|
||||||
|
},
|
||||||
class: {
|
class: {
|
||||||
Issue: '' as Ref<Class<Issue>>,
|
Issue: '' as Ref<Class<Issue>>,
|
||||||
Project: '' as Ref<Class<Project>>,
|
Project: '' as Ref<Class<Project>>,
|
||||||
@ -239,9 +268,6 @@ const task = plugin(taskId, {
|
|||||||
KanbanTemplateEditor: '' as AnyComponent,
|
KanbanTemplateEditor: '' as AnyComponent,
|
||||||
KanbanTemplateSelector: '' as AnyComponent,
|
KanbanTemplateSelector: '' as AnyComponent,
|
||||||
TodoItemsPopup: '' as AnyComponent
|
TodoItemsPopup: '' as AnyComponent
|
||||||
},
|
|
||||||
string: {
|
|
||||||
TodoItems: '' as IntlString
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user