diff --git a/packages/ui/src/components/icons/CheckCircle.svelte b/packages/ui/src/components/icons/CheckCircle.svelte new file mode 100644 index 0000000000..0915a5e1be --- /dev/null +++ b/packages/ui/src/components/icons/CheckCircle.svelte @@ -0,0 +1,12 @@ + + + + + diff --git a/packages/ui/src/components/icons/Info.svelte b/packages/ui/src/components/icons/Info.svelte index 0d7d93aced..0111c4e8b1 100644 --- a/packages/ui/src/components/icons/Info.svelte +++ b/packages/ui/src/components/icons/Info.svelte @@ -1,20 +1,20 @@ diff --git a/packages/ui/src/components/notifications/Notification.svelte b/packages/ui/src/components/notifications/Notification.svelte new file mode 100644 index 0000000000..d3fb5dfb5f --- /dev/null +++ b/packages/ui/src/components/notifications/Notification.svelte @@ -0,0 +1,26 @@ + + + diff --git a/packages/ui/src/components/notifications/Notification.ts b/packages/ui/src/components/notifications/Notification.ts new file mode 100644 index 0000000000..6066c477f3 --- /dev/null +++ b/packages/ui/src/components/notifications/Notification.ts @@ -0,0 +1,15 @@ +import { NotificationPosition } from './NotificationPosition' +import { NotificationSeverity } from './NotificationSeverity' +import { AnyComponent } from '../../types' + +export interface Notification { + id: string + title: string + component: AnyComponent + subTitle?: string + subTitlePostfix?: string + position: NotificationPosition + severity?: NotificationSeverity + params?: { [key: string]: any } + closeTimeout?: number +} diff --git a/packages/ui/src/components/notifications/NotificationPosition.ts b/packages/ui/src/components/notifications/NotificationPosition.ts new file mode 100644 index 0000000000..0b2deb904d --- /dev/null +++ b/packages/ui/src/components/notifications/NotificationPosition.ts @@ -0,0 +1,6 @@ +export enum NotificationPosition { + BottomLeft, + BottomRight, + TopLeft, + TopRight +} diff --git a/packages/ui/src/components/notifications/NotificationSeverity.ts b/packages/ui/src/components/notifications/NotificationSeverity.ts new file mode 100644 index 0000000000..5f24edc159 --- /dev/null +++ b/packages/ui/src/components/notifications/NotificationSeverity.ts @@ -0,0 +1,6 @@ +export enum NotificationSeverity { + Info, + Success, + Warning, + Error +} diff --git a/packages/ui/src/components/notifications/Notifications.svelte b/packages/ui/src/components/notifications/Notifications.svelte new file mode 100644 index 0000000000..f0678be64f --- /dev/null +++ b/packages/ui/src/components/notifications/Notifications.svelte @@ -0,0 +1,51 @@ + + + + + {#each Object.entries(positionByClassName) as [className, position]} + + {#each $store as notification (notification.id)} + {#if notification.position === position} + + {/if} + {/each} + + {/each} + + + diff --git a/packages/ui/src/components/notifications/actions.ts b/packages/ui/src/components/notifications/actions.ts new file mode 100644 index 0000000000..4efd422b04 --- /dev/null +++ b/packages/ui/src/components/notifications/actions.ts @@ -0,0 +1,34 @@ +import { Writable } from 'svelte/store' +import { generateId } from '@hcengineering/core' + +import { Notification } from './Notification' +import { NotificationPosition } from './NotificationPosition' +import { NotificationSeverity } from './NotificationSeverity' + +export const addNotification = (notification: Notification, store: Writable): void => { + if (notification === undefined || notification === null) { + return + } + + const { update } = store + + const newNotification = { + severity: NotificationSeverity.Info, + ...notification, + id: generateId() + } + + update((notifications: Notification[]) => + [NotificationPosition.TopRight, NotificationPosition.TopLeft].includes(newNotification.position) + ? [newNotification, ...notifications] + : [...notifications, newNotification] + ) +} + +export const removeNotification = (notificationId: string, { update }: Writable): void => { + if (notificationId === '') { + return + } + + update((notifications) => notifications.filter(({ id }) => id !== notificationId)) +} diff --git a/packages/ui/src/components/notifications/store.ts b/packages/ui/src/components/notifications/store.ts new file mode 100644 index 0000000000..63fb5bba24 --- /dev/null +++ b/packages/ui/src/components/notifications/store.ts @@ -0,0 +1,12 @@ +import { writable } from 'svelte/store' + +import { Notification } from './Notification' +import { addNotification, removeNotification } from './actions' + +const store = writable([]) + +export default { + subscribe: store.subscribe, + addNotification: (notification: Notification) => addNotification(notification, store), + removeNotification: (notificationId: string) => removeNotification(notificationId, store) +} diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts index 4c1e83286b..15553ed999 100644 --- a/packages/ui/src/index.ts +++ b/packages/ui/src/index.ts @@ -135,6 +135,7 @@ export { default as IconDetailsFilled } from './components/icons/DetailsFilled.s export { default as IconScale } from './components/icons/Scale.svelte' export { default as IconScaleFull } from './components/icons/ScaleFull.svelte' export { default as IconOpen } from './components/icons/Open.svelte' +export { default as IconCheckCircle } from './components/icons/CheckCircle.svelte' export { default as PanelInstance } from './components/PanelInstance.svelte' export { default as Panel } from './components/Panel.svelte' @@ -148,6 +149,11 @@ export { default as ListView } from './components/ListView.svelte' export { default as ToggleButton } from './components/ToggleButton.svelte' export { default as ExpandCollapse } from './components/ExpandCollapse.svelte' export { default as BarDashboard } from './components/BarDashboard.svelte' +export { default as Notifications } from './components/notifications/Notifications.svelte' +export { default as notificationsStore } from './components/notifications/store' +export { NotificationPosition } from './components/notifications/NotificationPosition' +export { NotificationSeverity } from './components/notifications/NotificationSeverity' +export { Notification } from './components/notifications/Notification' export * from './types' export * from './location' diff --git a/plugins/tracker-assets/lang/en.json b/plugins/tracker-assets/lang/en.json index 1f59733f48..9eff17f9bb 100644 --- a/plugins/tracker-assets/lang/en.json +++ b/plugins/tracker-assets/lang/en.json @@ -10,6 +10,8 @@ "Members": "Members", "Inbox": "Inbox", "MyIssues": "My issues", + "ViewIssue": "View issue", + "IssueCreated": "Issue Created", "Issues": "Issues", "Views": "Views", "Active": "Active", diff --git a/plugins/tracker-assets/lang/ru.json b/plugins/tracker-assets/lang/ru.json index b9552364b6..3e10f876d7 100644 --- a/plugins/tracker-assets/lang/ru.json +++ b/plugins/tracker-assets/lang/ru.json @@ -9,6 +9,8 @@ "Open": "Открыть", "Members": "Участиники", "Inbox": "Входящие", + "ViewIssue": "Открыть задачу", + "IssueCreated": "Задача создана", "MyIssues": "Мои задачи", "Issues": "Задачи", "Views": "Отображения", @@ -143,7 +145,7 @@ "FilterIsEither": "является ли любой из", "FilterStatesCount": "{value, plural, =1 {1 state} other {# states}}", "Assigned": "Назначенные", - "Created": "Созданные", + "Created": "{value, plural, =1 {Создана} other {Созданные}}", "Subscribed": "Отслеживаемые", "Relations": "Зависимости", diff --git a/plugins/tracker-resources/src/components/CreateIssue.svelte b/plugins/tracker-resources/src/components/CreateIssue.svelte index ed61953e3f..6e42fda623 100644 --- a/plugins/tracker-resources/src/components/CreateIssue.svelte +++ b/plugins/tracker-resources/src/components/CreateIssue.svelte @@ -1,14 +1,14 @@ @@ -17,7 +17,7 @@ import chunter from '@hcengineering/chunter' import { Employee } from '@hcengineering/contact' import core, { Account, AttachedData, Doc, generateId, Ref, SortingOrder, WithLookup } from '@hcengineering/core' - import { getResource } from '@hcengineering/platform' + import { getResource, translate } from '@hcengineering/platform' import { Card, createQuery, getClient, KeyedAttribute, MessageBox, SpaceSelector } from '@hcengineering/presentation' import tags, { TagElement, TagReference } from '@hcengineering/tags' import { @@ -42,7 +42,11 @@ Label, Menu, showPopup, - Spinner + Spinner, + NotificationPosition, + NotificationSeverity, + Notification, + notificationsStore } from '@hcengineering/ui' import view from '@hcengineering/view' import { ObjectBox } from '@hcengineering/view-resources' @@ -59,6 +63,7 @@ import SetParentIssueActionPopup from './SetParentIssueActionPopup.svelte' import SprintSelector from './sprints/SprintSelector.svelte' import IssueTemplateChilds from './templates/IssueTemplateChilds.svelte' + import IssueNotification from './issues/IssueNotification.svelte' export let space: Ref export let status: Ref | undefined = undefined @@ -394,6 +399,21 @@ } } + const notification: Notification = { + title: tracker.string.IssueCreated, + subTitle: getTitle(object.title), + severity: NotificationSeverity.Success, + position: NotificationPosition.BottomRight, + component: IssueNotification, + closeTimeout: 10000, + params: { + issueId: objectId, + subTitlePostfix: (await translate(tracker.string.Created, { value: 1 })).toLowerCase() + } + } + + notificationsStore.addNotification(notification) + objectId = generateId() resetObject() } diff --git a/plugins/tracker-resources/src/components/ModeSelector.svelte b/plugins/tracker-resources/src/components/ModeSelector.svelte index 7d4ece092e..2c5a80a770 100644 --- a/plugins/tracker-resources/src/components/ModeSelector.svelte +++ b/plugins/tracker-resources/src/components/ModeSelector.svelte @@ -3,7 +3,7 @@ import { Button } from '@hcengineering/ui' export let mode: string - export let config: [string, IntlString][] + export let config: [string, IntlString, object][] export let onChange: (_mode: string) => void function getButtonShape (i: number) { @@ -21,10 +21,11 @@ - {#each config as [_mode, label], i} + {#each config as [_mode, label, params], i} onChange(_mode)} selected={_mode === mode} diff --git a/plugins/tracker-resources/src/components/issues/IssueNotification.svelte b/plugins/tracker-resources/src/components/issues/IssueNotification.svelte new file mode 100644 index 0000000000..7c9eb271a7 --- /dev/null +++ b/plugins/tracker-resources/src/components/issues/IssueNotification.svelte @@ -0,0 +1,177 @@ + + + + + + + + + + + + {#if status} + + {/if} + {#if issue} + + {/if} + + {subTitle} + + + {params.subTitlePostfix} + + + + + + + + + + + + + + diff --git a/plugins/tracker-resources/src/components/issues/IssuePresenter.svelte b/plugins/tracker-resources/src/components/issues/IssuePresenter.svelte index cbbb19326c..dc84046765 100644 --- a/plugins/tracker-resources/src/components/issues/IssuePresenter.svelte +++ b/plugins/tracker-resources/src/components/issues/IssuePresenter.svelte @@ -1,14 +1,14 @@ @@ -20,13 +20,18 @@ import tracker from '../../plugin' export let value: WithLookup - // export let inline: boolean = false export let disableClick = false + export let onClick: () => void function handleIssueEditorOpened () { if (disableClick) { return } + + if (onClick) { + onClick() + } + showPanel(tracker.component.EditIssue, value._id, value._class, 'content') } diff --git a/plugins/tracker-resources/src/components/myissues/MyIssues.svelte b/plugins/tracker-resources/src/components/myissues/MyIssues.svelte index fa9bc2a7b1..e41d14fe5a 100644 --- a/plugins/tracker-resources/src/components/myissues/MyIssues.svelte +++ b/plugins/tracker-resources/src/components/myissues/MyIssues.svelte @@ -1,14 +1,14 @@ @@ -26,9 +26,9 @@ import IssuesView from '../issues/IssuesView.svelte' import ModeSelector from '../ModeSelector.svelte' - const config: [string, IntlString][] = [ + const config: [string, IntlString, object][] = [ ['assigned', tracker.string.Assigned], - ['created', tracker.string.Created], + ['created', tracker.string.Created, { value: 0 }], ['subscribed', tracker.string.Subscribed] ] const currentUser = getCurrentAccount() as EmployeeAccount diff --git a/plugins/tracker-resources/src/plugin.ts b/plugins/tracker-resources/src/plugin.ts index 16c4857b7b..acdb034fb1 100644 --- a/plugins/tracker-resources/src/plugin.ts +++ b/plugins/tracker-resources/src/plugin.ts @@ -28,6 +28,8 @@ export default mergeIds(trackerId, tracker, { Members: '' as IntlString, Inbox: '' as IntlString, MyIssues: '' as IntlString, + ViewIssue: '' as IntlString, + IssueCreated: '' as IntlString, Issues: '' as IntlString, Views: '' as IntlString, Active: '' as IntlString, diff --git a/plugins/workbench-resources/src/components/WorkbenchApp.svelte b/plugins/workbench-resources/src/components/WorkbenchApp.svelte index 523b11806c..9b51a44337 100644 --- a/plugins/workbench-resources/src/components/WorkbenchApp.svelte +++ b/plugins/workbench-resources/src/components/WorkbenchApp.svelte @@ -1,22 +1,22 @@ @@ -30,7 +30,9 @@ {versionError} {:else if client} - + + + {/if} {:catch error} {error} -- {error.stack}