mirror of
https://github.com/hcengineering/platform.git
synced 2025-03-19 05:08:12 +00:00
Merge remote-tracking branch 'origin/develop' into staging
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
commit
f72dd3b513
@ -1140,7 +1140,8 @@ export function devTool (
|
|||||||
.option('-bl, --blobLimit <blobLimit>', 'A blob size limit in megabytes (default 50mb)', '50')
|
.option('-bl, --blobLimit <blobLimit>', 'A blob size limit in megabytes (default 50mb)', '50')
|
||||||
.option('-c, --concurrency <concurrency>', 'Number of files being processed concurrently', '10')
|
.option('-c, --concurrency <concurrency>', 'Number of files being processed concurrently', '10')
|
||||||
.option('--disabled', 'Include disabled workspaces', false)
|
.option('--disabled', 'Include disabled workspaces', false)
|
||||||
.action(async (cmd: { workspace: string, move: string, blobLimit: string, concurrency: string, disabled: boolean }) => {
|
.action(
|
||||||
|
async (cmd: { workspace: string, move: string, blobLimit: string, concurrency: string, disabled: boolean }) => {
|
||||||
const params = {
|
const params = {
|
||||||
blobSizeLimitMb: parseInt(cmd.blobLimit),
|
blobSizeLimitMb: parseInt(cmd.blobLimit),
|
||||||
concurrency: parseInt(cmd.concurrency),
|
concurrency: parseInt(cmd.concurrency),
|
||||||
@ -1182,7 +1183,8 @@ export function devTool (
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
program
|
program
|
||||||
.command('sync-files')
|
.command('sync-files')
|
||||||
|
@ -105,6 +105,10 @@ export class TBrowserNotification extends TDoc implements BrowserNotification {
|
|||||||
onClickLocation?: Location | undefined
|
onClickLocation?: Location | undefined
|
||||||
user!: Ref<Account>
|
user!: Ref<Account>
|
||||||
status!: NotificationStatus
|
status!: NotificationStatus
|
||||||
|
messageId?: Ref<ActivityMessage>
|
||||||
|
messageClass?: Ref<Class<ActivityMessage>>
|
||||||
|
objectId!: Ref<Doc>
|
||||||
|
objectClass!: Ref<Class<Doc>>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Model(notification.class.PushSubscription, core.class.Doc, DOMAIN_USER_NOTIFY)
|
@Model(notification.class.PushSubscription, core.class.Doc, DOMAIN_USER_NOTIFY)
|
||||||
|
@ -34,7 +34,6 @@ export default mergeIds(timeId, time, {
|
|||||||
EditToDo: '' as IntlString,
|
EditToDo: '' as IntlString,
|
||||||
GotoTimePlaning: '' as IntlString,
|
GotoTimePlaning: '' as IntlString,
|
||||||
GotoTimeTeamPlaning: '' as IntlString,
|
GotoTimeTeamPlaning: '' as IntlString,
|
||||||
NewToDo: '' as IntlString,
|
|
||||||
Priority: '' as IntlString,
|
Priority: '' as IntlString,
|
||||||
MarkedAsDone: '' as IntlString
|
MarkedAsDone: '' as IntlString
|
||||||
},
|
},
|
||||||
|
@ -1,3 +1,177 @@
|
|||||||
|
.hulyButton {
|
||||||
|
display: inline-flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
gap: var(--spacing-1);
|
||||||
|
border: 1px solid transparent;
|
||||||
|
|
||||||
|
&:not(:disabled, .disabled, .loading) { cursor: pointer; }
|
||||||
|
&.inheritFont { font: inherit; }
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: var(--spacing-2_5);
|
||||||
|
height: var(--spacing-2_5);
|
||||||
|
}
|
||||||
|
span { white-space: nowrap; }
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: 2px solid var(--global-focus-BorderColor);
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
&.type-button-icon { padding: 0; }
|
||||||
|
&.large {
|
||||||
|
height: var(--global-large-Size);
|
||||||
|
border-radius: var(--medium-BorderRadius);
|
||||||
|
|
||||||
|
&.round { border-radius: var(--large-BorderRadius); }
|
||||||
|
|
||||||
|
&.type-button:not(.iconOnly) { padding: 0 var(--spacing-2); }
|
||||||
|
&.iconOnly,
|
||||||
|
&.type-button-icon { width: var(--global-large-Size); }
|
||||||
|
}
|
||||||
|
&.medium {
|
||||||
|
height: var(--global-medium-Size);
|
||||||
|
border-radius: var(--medium-BorderRadius);
|
||||||
|
|
||||||
|
&.round { border-radius: var(--large-BorderRadius); }
|
||||||
|
&.type-button:not(.iconOnly) { padding: 0 var(--spacing-2); }
|
||||||
|
&.iconOnly,
|
||||||
|
&.type-button-icon { width: var(--global-medium-Size); }
|
||||||
|
}
|
||||||
|
&.small {
|
||||||
|
height: var(--global-small-Size);
|
||||||
|
gap: var(--spacing-0_5);
|
||||||
|
border-radius: var(--small-BorderRadius);
|
||||||
|
|
||||||
|
&.round { border-radius: var(--large-BorderRadius); }
|
||||||
|
&.type-button:not(.iconOnly) { padding: 0 var(--spacing-1); }
|
||||||
|
&.iconOnly,
|
||||||
|
&.type-button-icon { width: var(--global-small-Size); }
|
||||||
|
}
|
||||||
|
&.extra-small {
|
||||||
|
height: var(--global-extra-small-Size);
|
||||||
|
border-radius: var(--extra-small-BorderRadius);
|
||||||
|
|
||||||
|
&.round { border-radius: var(--large-BorderRadius); }
|
||||||
|
&.type-button:not(.iconOnly) { padding: 0 var(--spacing-1); }
|
||||||
|
&.iconOnly,
|
||||||
|
&.type-button-icon { width: var(--global-extra-small-Size); }
|
||||||
|
}
|
||||||
|
&.min {
|
||||||
|
height: var(--global-min-Size);
|
||||||
|
border: 0;
|
||||||
|
border-radius: var(--min-BorderRadius);
|
||||||
|
}
|
||||||
|
&.type-button-icon .icon,
|
||||||
|
&.menu .icon {
|
||||||
|
width: var(--spacing-2);
|
||||||
|
height: var(--spacing-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled:not(.loading),
|
||||||
|
&.disabled:not(.loading) {
|
||||||
|
border-color: transparent;
|
||||||
|
cursor: not-allowed;
|
||||||
|
|
||||||
|
.icon { color: var(--button-disabled-IconColor); }
|
||||||
|
span { color: var(--button-disabled-LabelColor); }
|
||||||
|
}
|
||||||
|
|
||||||
|
&.primary {
|
||||||
|
border-color: var(--button-primary-BorderColor);
|
||||||
|
background-color: var(--button-primary-BackgroundColor);
|
||||||
|
|
||||||
|
.icon { color: var(--button-accent-IconColor); }
|
||||||
|
span { color: var(--button-accent-LabelColor); }
|
||||||
|
|
||||||
|
&:not(.disabled, :disabled):hover { background-color: var(--button-primary-hover-BackgroundColor); }
|
||||||
|
&:not(.disabled, :disabled):active,
|
||||||
|
&.pressed:not(.disabled, :disabled) { background-color: var(--button-primary-active-BackgroundColor); }
|
||||||
|
&.menu:not(.disabled, :disabled):active,
|
||||||
|
&.pressed:not(.disabled, :disabled) { border-color: var(--button-menu-active-BorderColor); }
|
||||||
|
&:disabled:not(.loading),
|
||||||
|
&.disabled:not(.loading) { background-color: var(--button-disabled-BackgroundColor); }
|
||||||
|
&.loading {
|
||||||
|
background-color: var(--button-primary-active-BackgroundColor);
|
||||||
|
|
||||||
|
span { color: var(--button-primary-loading-LabelColor); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.secondary {
|
||||||
|
border-color: var(--button-secondary-BorderColor);
|
||||||
|
background-color: var(--button-secondary-BackgroundColor);
|
||||||
|
|
||||||
|
.icon { color: var(--button-subtle-IconColor); }
|
||||||
|
span { color: var(--button-subtle-LabelColor); }
|
||||||
|
|
||||||
|
&:not(.disabled, :disabled):hover { background-color: var(--button-secondary-hover-BackgroundColor); }
|
||||||
|
&:not(.disabled, :disabled):active,
|
||||||
|
&.pressed:not(.disabled, :disabled) { background-color: var(--button-secondary-active-BackgroundColor); }
|
||||||
|
&.menu:not(.disabled, :disabled):active,
|
||||||
|
&.pressed:not(.disabled, :disabled) { border-color: var(--button-menu-active-BorderColor); }
|
||||||
|
&:disabled:not(.loading),
|
||||||
|
&.disabled:not(.loading) { background-color: var(--button-disabled-BackgroundColor); }
|
||||||
|
&.loading {
|
||||||
|
background-color: var(--button-secondary-active-BackgroundColor);
|
||||||
|
|
||||||
|
span { color: var(--button-disabled-LabelColor); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.tertiary {
|
||||||
|
border-color: transparent;
|
||||||
|
background-color: transparent;
|
||||||
|
|
||||||
|
&:not(.inheritColor) .icon { color: var(--button-subtle-IconColor); }
|
||||||
|
&.inheritColor {
|
||||||
|
color: inherit;
|
||||||
|
|
||||||
|
.icon { color: currentColor; }
|
||||||
|
}
|
||||||
|
span { color: var(--button-subtle-LabelColor); }
|
||||||
|
|
||||||
|
&:not(.disabled, :disabled):hover { background-color: var(--button-tertiary-hover-BackgroundColor); }
|
||||||
|
&:not(.disabled, :disabled):active,
|
||||||
|
&.pressed:not(.disabled, :disabled) { background-color: var(--button-tertiary-active-BackgroundColor); }
|
||||||
|
&.menu:not(.disabled, :disabled):active,
|
||||||
|
&.pressed:not(.disabled, :disabled) { border-color: var(--button-menu-active-BorderColor); }
|
||||||
|
&.loading {
|
||||||
|
background-color: var(--button-tertiary-active-BackgroundColor);
|
||||||
|
|
||||||
|
span { color: var(--button-disabled-LabelColor); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.negative {
|
||||||
|
border-color: var(--button-negative-BorderColor);
|
||||||
|
background-color: var(--button-negative-BackgroundColor);
|
||||||
|
|
||||||
|
.icon { color: var(--button-accent-IconColor); }
|
||||||
|
span { color: var(--button-accent-LabelColor); }
|
||||||
|
|
||||||
|
&:not(.disabled, :disabled):hover { background-color: var(--button-negative-hover-BackgroundColor); }
|
||||||
|
&:not(.disabled, :disabled):active,
|
||||||
|
&.pressed:not(.disabled, :disabled) { background-color: var(--button-negative-active-BackgroundColor); }
|
||||||
|
&.menu:not(.disabled, :disabled):active,
|
||||||
|
&.pressed:not(.disabled, :disabled) { border-color: var(--button-menu-active-BorderColor); }
|
||||||
|
&:disabled:not(.loading),
|
||||||
|
&.disabled:not(.loading) { background-color: var(--button-disabled-BackgroundColor); }
|
||||||
|
&.loading {
|
||||||
|
background-color: var(--button-negative-active-BackgroundColor);
|
||||||
|
|
||||||
|
span { color: var(--button-negative-loading-LabelColor); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& > * { pointer-events: none; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Old style Button
|
||||||
.antiButton {
|
.antiButton {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -92,7 +92,7 @@
|
|||||||
<button
|
<button
|
||||||
{id}
|
{id}
|
||||||
bind:this={element}
|
bind:this={element}
|
||||||
class="font-medium-14 {kind} {size} {type} {shape}"
|
class="hulyButton font-medium-14 {kind} {size} {type} {shape}"
|
||||||
class:loading
|
class:loading
|
||||||
class:pressed
|
class:pressed
|
||||||
class:inheritColor
|
class:inheritColor
|
||||||
@ -115,300 +115,3 @@
|
|||||||
{#if title}<span>{title}</span>{/if}
|
{#if title}<span>{title}</span>{/if}
|
||||||
<slot />
|
<slot />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
button {
|
|
||||||
display: inline-flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
flex-shrink: 0;
|
|
||||||
gap: var(--spacing-1);
|
|
||||||
|
|
||||||
border: 1px solid transparent;
|
|
||||||
|
|
||||||
&:not(:disabled, .loading) {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
&.inheritFont {
|
|
||||||
font: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: var(--spacing-2_5);
|
|
||||||
height: var(--spacing-2_5);
|
|
||||||
}
|
|
||||||
span {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
outline: 2px solid var(--global-focus-BorderColor);
|
|
||||||
outline-offset: 2px;
|
|
||||||
}
|
|
||||||
&.type-button-icon {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
&.large {
|
|
||||||
height: var(--global-large-Size);
|
|
||||||
border-radius: var(--medium-BorderRadius);
|
|
||||||
|
|
||||||
&.round {
|
|
||||||
border-radius: var(--large-BorderRadius);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.type-button:not(.iconOnly) {
|
|
||||||
padding: 0 var(--spacing-2);
|
|
||||||
}
|
|
||||||
&.iconOnly,
|
|
||||||
&.type-button-icon {
|
|
||||||
width: var(--global-large-Size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.medium {
|
|
||||||
height: var(--global-medium-Size);
|
|
||||||
border-radius: var(--medium-BorderRadius);
|
|
||||||
|
|
||||||
&.round {
|
|
||||||
border-radius: var(--large-BorderRadius);
|
|
||||||
}
|
|
||||||
&.type-button:not(.iconOnly) {
|
|
||||||
padding: 0 var(--spacing-2);
|
|
||||||
}
|
|
||||||
&.iconOnly,
|
|
||||||
&.type-button-icon {
|
|
||||||
width: var(--global-medium-Size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.small {
|
|
||||||
height: var(--global-small-Size);
|
|
||||||
gap: var(--spacing-0_5);
|
|
||||||
border-radius: var(--small-BorderRadius);
|
|
||||||
|
|
||||||
&.round {
|
|
||||||
border-radius: var(--large-BorderRadius);
|
|
||||||
}
|
|
||||||
&.type-button:not(.iconOnly) {
|
|
||||||
padding: 0 var(--spacing-1);
|
|
||||||
}
|
|
||||||
&.iconOnly,
|
|
||||||
&.type-button-icon {
|
|
||||||
width: var(--global-small-Size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.extra-small {
|
|
||||||
height: var(--global-extra-small-Size);
|
|
||||||
border-radius: var(--extra-small-BorderRadius);
|
|
||||||
|
|
||||||
&.round {
|
|
||||||
border-radius: var(--large-BorderRadius);
|
|
||||||
}
|
|
||||||
&.type-button:not(.iconOnly) {
|
|
||||||
padding: 0 var(--spacing-1);
|
|
||||||
}
|
|
||||||
&.iconOnly,
|
|
||||||
&.type-button-icon {
|
|
||||||
width: var(--global-extra-small-Size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.min {
|
|
||||||
height: var(--global-min-Size);
|
|
||||||
border: 0;
|
|
||||||
border-radius: var(--min-BorderRadius);
|
|
||||||
}
|
|
||||||
&.type-button-icon .icon,
|
|
||||||
&.menu .icon {
|
|
||||||
width: var(--spacing-2);
|
|
||||||
height: var(--spacing-2);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.primary {
|
|
||||||
border-color: var(--button-primary-BorderColor);
|
|
||||||
background-color: var(--button-primary-BackgroundColor);
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
color: var(--button-accent-IconColor);
|
|
||||||
}
|
|
||||||
span {
|
|
||||||
color: var(--button-accent-LabelColor);
|
|
||||||
}
|
|
||||||
&:hover {
|
|
||||||
background-color: var(--button-primary-hover-BackgroundColor);
|
|
||||||
}
|
|
||||||
&:active,
|
|
||||||
&.pressed {
|
|
||||||
background-color: var(--button-primary-active-BackgroundColor);
|
|
||||||
}
|
|
||||||
&.menu:enabled:active,
|
|
||||||
&.pressed {
|
|
||||||
border-color: var(--button-menu-active-BorderColor);
|
|
||||||
}
|
|
||||||
&:disabled:not(.loading) {
|
|
||||||
background-color: var(--button-disabled-BackgroundColor);
|
|
||||||
border-color: transparent;
|
|
||||||
cursor: not-allowed;
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
color: var(--button-disabled-IconColor);
|
|
||||||
}
|
|
||||||
span {
|
|
||||||
color: var(--button-disabled-LabelColor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.loading {
|
|
||||||
background-color: var(--button-primary-active-BackgroundColor);
|
|
||||||
|
|
||||||
span {
|
|
||||||
color: var(--button-primary-loading-LabelColor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.secondary {
|
|
||||||
border-color: var(--button-secondary-BorderColor);
|
|
||||||
background-color: var(--button-secondary-BackgroundColor);
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
color: var(--button-subtle-IconColor);
|
|
||||||
}
|
|
||||||
span {
|
|
||||||
color: var(--button-subtle-LabelColor);
|
|
||||||
}
|
|
||||||
&:hover {
|
|
||||||
background-color: var(--button-secondary-hover-BackgroundColor);
|
|
||||||
}
|
|
||||||
&:active,
|
|
||||||
&.pressed {
|
|
||||||
background-color: var(--button-secondary-active-BackgroundColor);
|
|
||||||
}
|
|
||||||
&.menu:enabled:active,
|
|
||||||
&.pressed {
|
|
||||||
border-color: var(--button-menu-active-BorderColor);
|
|
||||||
}
|
|
||||||
&:disabled:not(.loading) {
|
|
||||||
background-color: var(--button-disabled-BackgroundColor);
|
|
||||||
border-color: transparent;
|
|
||||||
cursor: not-allowed;
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
color: var(--button-disabled-IconColor);
|
|
||||||
}
|
|
||||||
span {
|
|
||||||
color: var(--button-disabled-LabelColor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.loading {
|
|
||||||
background-color: var(--button-secondary-active-BackgroundColor);
|
|
||||||
|
|
||||||
span {
|
|
||||||
color: var(--button-disabled-LabelColor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.tertiary {
|
|
||||||
border-color: transparent;
|
|
||||||
background-color: transparent;
|
|
||||||
|
|
||||||
&:not(.inheritColor) .icon {
|
|
||||||
color: var(--button-subtle-IconColor);
|
|
||||||
}
|
|
||||||
&.inheritColor {
|
|
||||||
color: inherit;
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
color: currentColor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
span {
|
|
||||||
color: var(--button-subtle-LabelColor);
|
|
||||||
}
|
|
||||||
&:hover:enabled {
|
|
||||||
background-color: var(--button-tertiary-hover-BackgroundColor);
|
|
||||||
}
|
|
||||||
&:active:enabled,
|
|
||||||
&.pressed:enabled {
|
|
||||||
background-color: var(--button-tertiary-active-BackgroundColor);
|
|
||||||
}
|
|
||||||
&.menu:active:enabled,
|
|
||||||
&.pressed:enabled {
|
|
||||||
border-color: var(--button-menu-active-BorderColor);
|
|
||||||
}
|
|
||||||
&:disabled:not(.loading) {
|
|
||||||
border-color: transparent;
|
|
||||||
cursor: not-allowed;
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
color: var(--button-disabled-IconColor);
|
|
||||||
}
|
|
||||||
span {
|
|
||||||
color: var(--button-disabled-LabelColor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.loading {
|
|
||||||
background-color: var(--button-tertiary-active-BackgroundColor);
|
|
||||||
|
|
||||||
span {
|
|
||||||
color: var(--button-disabled-LabelColor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.negative {
|
|
||||||
border-color: var(--button-negative-BorderColor);
|
|
||||||
background-color: var(--button-negative-BackgroundColor);
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
color: var(--button-accent-IconColor);
|
|
||||||
}
|
|
||||||
span {
|
|
||||||
color: var(--button-accent-LabelColor);
|
|
||||||
}
|
|
||||||
&:hover {
|
|
||||||
background-color: var(--button-negative-hover-BackgroundColor);
|
|
||||||
}
|
|
||||||
&:active,
|
|
||||||
&.pressed {
|
|
||||||
background-color: var(--button-negative-active-BackgroundColor);
|
|
||||||
}
|
|
||||||
&.menu:enabled:active,
|
|
||||||
&.pressed {
|
|
||||||
border-color: var(--button-menu-active-BorderColor);
|
|
||||||
}
|
|
||||||
&:disabled:not(.loading) {
|
|
||||||
background-color: var(--button-disabled-BackgroundColor);
|
|
||||||
border-color: transparent;
|
|
||||||
cursor: not-allowed;
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
color: var(--button-disabled-IconColor);
|
|
||||||
}
|
|
||||||
span {
|
|
||||||
color: var(--button-disabled-LabelColor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.loading {
|
|
||||||
background-color: var(--button-negative-active-BackgroundColor);
|
|
||||||
|
|
||||||
span {
|
|
||||||
color: var(--button-negative-loading-LabelColor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& > * {
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes rotate {
|
|
||||||
0% {
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: rotate(359deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
@ -153,7 +153,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const focused = (ed: TEdits): void => {
|
export const focused = (ed: TEdits): void => {
|
||||||
selected = ed
|
selected = ed
|
||||||
startTyping = true
|
startTyping = true
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
export let date: number
|
export let date: number
|
||||||
export let difference: number = 0
|
export let difference: number = 0
|
||||||
export let direction: 'vertical' | 'horizontal' = 'vertical'
|
export let direction: 'vertical' | 'horizontal' | 'auto' = 'vertical'
|
||||||
export let showDate: boolean = true
|
export let showDate: boolean = true
|
||||||
export let withoutTime: boolean
|
export let withoutTime: boolean
|
||||||
export let kind: ButtonBaseKind = 'tertiary'
|
export let kind: ButtonBaseKind = 'tertiary'
|
||||||
@ -44,8 +44,9 @@
|
|||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
$: currentDate = new Date(date)
|
$: currentDate = new Date(date)
|
||||||
|
let tib: TimeInputBox
|
||||||
|
|
||||||
function timeClick (e: MouseEvent) {
|
function timeClick (e: MouseEvent & { currentTarget: EventTarget & HTMLElement }) {
|
||||||
if (!showDate) {
|
if (!showDate) {
|
||||||
showPopup(
|
showPopup(
|
||||||
DatePopup,
|
DatePopup,
|
||||||
@ -58,7 +59,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
} else if (!disabled) tib.focused(e.offsetX <= e.currentTarget.clientWidth / 2 ? 'hour' : 'min')
|
||||||
}
|
}
|
||||||
|
|
||||||
function dateClick (e: MouseEvent) {
|
function dateClick (e: MouseEvent) {
|
||||||
@ -85,13 +86,17 @@
|
|||||||
{#if fixed === undefined}
|
{#if fixed === undefined}
|
||||||
<div class="min-w-28">
|
<div class="min-w-28">
|
||||||
<ButtonBase type="type-button" {kind} {size} {disabled} {focusIndex} on:click={dateClick}>
|
<ButtonBase type="type-button" {kind} {size} {disabled} {focusIndex} on:click={dateClick}>
|
||||||
<span class="overflow-label"><DateLocalePresenter date={currentDate.getTime()} {timeZone} /></span>
|
<span class="overflow-label tertiary-textColor">
|
||||||
|
<DateLocalePresenter date={currentDate.getTime()} {timeZone} />
|
||||||
|
</span>
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<FixedColumn key={fixed + '-date'} addClass={'min-w-28'}>
|
<FixedColumn key={fixed + '-date'} addClass={'min-w-28'}>
|
||||||
<ButtonBase type="type-button" {kind} {size} {disabled} {focusIndex} on:click={dateClick}>
|
<ButtonBase type="type-button" {kind} {size} {disabled} {focusIndex} on:click={dateClick}>
|
||||||
<span class="overflow-label"><DateLocalePresenter date={currentDate.getTime()} {timeZone} /></span>
|
<span class="overflow-label tertiary-textColor">
|
||||||
|
<DateLocalePresenter date={currentDate.getTime()} {timeZone} />
|
||||||
|
</span>
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
</FixedColumn>
|
</FixedColumn>
|
||||||
{/if}
|
{/if}
|
||||||
@ -103,15 +108,17 @@
|
|||||||
|
|
||||||
{#if !withoutTime}
|
{#if !withoutTime}
|
||||||
{#if fixed === undefined}
|
{#if fixed === undefined}
|
||||||
<ButtonBase
|
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||||
type="type-button"
|
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||||
{kind}
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
{size}
|
<div
|
||||||
{disabled}
|
class="hulyButton type-button tertiary small rectangle font-medium-14"
|
||||||
focusIndex={focusIndex !== -1 ? focusIndex + 1 : focusIndex}
|
class:disabled
|
||||||
|
tabindex={focusIndex !== -1 ? focusIndex + 1 : focusIndex}
|
||||||
on:click={timeClick}
|
on:click={timeClick}
|
||||||
>
|
>
|
||||||
<TimeInputBox
|
<TimeInputBox
|
||||||
|
bind:this={tib}
|
||||||
bind:currentDate
|
bind:currentDate
|
||||||
{timeZone}
|
{timeZone}
|
||||||
noBorder
|
noBorder
|
||||||
@ -120,18 +127,20 @@
|
|||||||
updateTime(date.detail)
|
updateTime(date.detail)
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</ButtonBase>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<FixedColumn key={fixed + '-time'} addClass={'min-w-28'}>
|
<FixedColumn key={fixed + '-time'} addClass={'min-w-28'}>
|
||||||
<ButtonBase
|
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||||
type="type-button"
|
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||||
{kind}
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
{size}
|
<div
|
||||||
{disabled}
|
class="hulyButton type-button tertiary small rectangle font-medium-14"
|
||||||
focusIndex={focusIndex !== -1 ? focusIndex + 1 : focusIndex}
|
class:disabled
|
||||||
|
tabindex={focusIndex !== -1 ? focusIndex + 1 : focusIndex}
|
||||||
on:click={timeClick}
|
on:click={timeClick}
|
||||||
>
|
>
|
||||||
<TimeInputBox
|
<TimeInputBox
|
||||||
|
bind:this={tib}
|
||||||
bind:currentDate
|
bind:currentDate
|
||||||
{timeZone}
|
{timeZone}
|
||||||
noBorder
|
noBorder
|
||||||
@ -140,7 +149,7 @@
|
|||||||
updateTime(date.detail)
|
updateTime(date.detail)
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</ButtonBase>
|
</div>
|
||||||
</FixedColumn>
|
</FixedColumn>
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
@ -162,9 +171,15 @@
|
|||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.dateEditor-container {
|
.dateEditor-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: nowrap;
|
|
||||||
|
|
||||||
&.horizontal {
|
&:not(.auto) {
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
}
|
||||||
|
&.auto {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
&.horizontal,
|
||||||
|
&.auto {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
&.vertical {
|
&.vertical {
|
||||||
|
@ -31,14 +31,15 @@
|
|||||||
export let isAsideOpened = false
|
export let isAsideOpened = false
|
||||||
export let syncLocation = true
|
export let syncLocation = true
|
||||||
export let freeze = false
|
export let freeze = false
|
||||||
|
export let selectedMessageId: Ref<ActivityMessage> | undefined = undefined
|
||||||
|
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
const hierarchy = client.getHierarchy()
|
const hierarchy = client.getHierarchy()
|
||||||
|
|
||||||
let dataProvider: ChannelDataProvider | undefined
|
let dataProvider: ChannelDataProvider | undefined
|
||||||
let selectedMessageId: Ref<ActivityMessage> | undefined = undefined
|
|
||||||
|
|
||||||
const unsubscribe = messageInFocus.subscribe((id) => {
|
const unsubscribe = messageInFocus.subscribe((id) => {
|
||||||
|
if (!syncLocation) return
|
||||||
if (id !== undefined && id !== selectedMessageId) {
|
if (id !== undefined && id !== selectedMessageId) {
|
||||||
selectedMessageId = id
|
selectedMessageId = id
|
||||||
}
|
}
|
||||||
@ -47,9 +48,7 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
const unsubscribeLocation = locationStore.subscribe((newLocation) => {
|
const unsubscribeLocation = locationStore.subscribe((newLocation) => {
|
||||||
if (!syncLocation) {
|
if (!syncLocation) return
|
||||||
return
|
|
||||||
}
|
|
||||||
const id = getMessageFromLoc(newLocation)
|
const id = getMessageFromLoc(newLocation)
|
||||||
selectedMessageId = id
|
selectedMessageId = id
|
||||||
messageInFocus.set(id)
|
messageInFocus.set(id)
|
||||||
|
@ -582,13 +582,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function restoreScroll () {
|
async function restoreScroll () {
|
||||||
if (!scrollElement || !scroller) {
|
await wait()
|
||||||
|
|
||||||
|
if (!scrollElement || !scroller || scrollToRestore === 0) {
|
||||||
scrollToRestore = 0
|
scrollToRestore = 0
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
await wait()
|
|
||||||
|
|
||||||
const delta = scrollElement.scrollHeight - scrollToRestore
|
const delta = scrollElement.scrollHeight - scrollToRestore
|
||||||
|
|
||||||
scroller.scrollBy(delta)
|
scroller.scrollBy(delta)
|
||||||
|
@ -18,7 +18,9 @@
|
|||||||
import { DocNotifyContext } from '@hcengineering/notification'
|
import { DocNotifyContext } from '@hcengineering/notification'
|
||||||
import { InboxNotificationsClientImpl } from '@hcengineering/notification-resources'
|
import { InboxNotificationsClientImpl } from '@hcengineering/notification-resources'
|
||||||
import { Widget } from '@hcengineering/workbench'
|
import { Widget } from '@hcengineering/workbench'
|
||||||
|
import { ActivityMessage } from '@hcengineering/activity'
|
||||||
import { ChatWidgetTab } from '@hcengineering/chunter'
|
import { ChatWidgetTab } from '@hcengineering/chunter'
|
||||||
|
import { updateTabData } from '@hcengineering/workbench-resources'
|
||||||
|
|
||||||
import Channel from './Channel.svelte'
|
import Channel from './Channel.svelte'
|
||||||
import { closeThreadInSidebarChannel } from '../navigation'
|
import { closeThreadInSidebarChannel } from '../navigation'
|
||||||
@ -36,12 +38,18 @@
|
|||||||
|
|
||||||
let object: Doc | undefined = undefined
|
let object: Doc | undefined = undefined
|
||||||
let context: DocNotifyContext | undefined = undefined
|
let context: DocNotifyContext | undefined = undefined
|
||||||
|
let selectedMessageId: Ref<ActivityMessage> | undefined = tab.data.selectedMessageId
|
||||||
|
|
||||||
$: context = object ? $contextByDocStore.get(object._id) : undefined
|
$: context = object ? $contextByDocStore.get(object._id) : undefined
|
||||||
$: void loadObject(tab.data._id, tab.data._class)
|
$: void loadObject(tab.data._id, tab.data._class)
|
||||||
|
|
||||||
$: threadId = tab.data.thread
|
$: threadId = tab.data.thread
|
||||||
|
|
||||||
|
$: if (tab.data.selectedMessageId !== undefined && tab.data.selectedMessageId !== '') {
|
||||||
|
selectedMessageId = tab.data.selectedMessageId
|
||||||
|
updateTabData(widget._id, tab.id, { selectedMessageId: '' })
|
||||||
|
}
|
||||||
|
|
||||||
async function loadObject (_id?: Ref<Doc>, _class?: Ref<Class<Doc>>): Promise<void> {
|
async function loadObject (_id?: Ref<Doc>, _class?: Ref<Class<Doc>>): Promise<void> {
|
||||||
if (_id === undefined || _class === undefined) {
|
if (_id === undefined || _class === undefined) {
|
||||||
object = undefined
|
object = undefined
|
||||||
@ -80,13 +88,19 @@
|
|||||||
on:close
|
on:close
|
||||||
/>
|
/>
|
||||||
{#key object._id}
|
{#key object._id}
|
||||||
<Channel {object} {context} syncLocation={false} freeze={threadId !== undefined} />
|
<Channel {object} {context} syncLocation={false} freeze={threadId !== undefined} {selectedMessageId} />
|
||||||
{/key}
|
{/key}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if threadId}
|
{#if threadId}
|
||||||
<div class="thread" style:height style:width>
|
<div class="thread" style:height style:width>
|
||||||
<ThreadView _id={threadId} on:channel={() => closeThreadInSidebarChannel(widget, tab)} on:close />
|
<ThreadView
|
||||||
|
_id={threadId}
|
||||||
|
{selectedMessageId}
|
||||||
|
syncLocation={false}
|
||||||
|
on:channel={() => closeThreadInSidebarChannel(widget, tab)}
|
||||||
|
on:close
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
@ -0,0 +1,79 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import activity, { ActivityMessage } from '@hcengineering/activity'
|
||||||
|
import ThreadParentMessage from './ThreadParentPresenter.svelte'
|
||||||
|
import { Label } from '@hcengineering/ui'
|
||||||
|
import ChannelScrollView from '../ChannelScrollView.svelte'
|
||||||
|
import { Ref } from '@hcengineering/core'
|
||||||
|
import { ChannelDataProvider } from '../../channelDataProvider'
|
||||||
|
import chunter from '../../plugin'
|
||||||
|
|
||||||
|
export let selectedMessageId: Ref<ActivityMessage> | undefined = undefined
|
||||||
|
export let message: ActivityMessage
|
||||||
|
|
||||||
|
let dataProvider: ChannelDataProvider | undefined = undefined
|
||||||
|
|
||||||
|
$: if (message !== undefined && dataProvider === undefined) {
|
||||||
|
dataProvider = new ChannelDataProvider(
|
||||||
|
undefined,
|
||||||
|
message.space,
|
||||||
|
message._id,
|
||||||
|
chunter.class.ThreadMessage,
|
||||||
|
selectedMessageId,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
$: messagesStore = dataProvider?.messagesStore
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="hulyComponent-content hulyComponent-content__container noShrink">
|
||||||
|
{#if dataProvider !== undefined}
|
||||||
|
<ChannelScrollView
|
||||||
|
bind:selectedMessageId
|
||||||
|
embedded
|
||||||
|
skipLabels
|
||||||
|
object={message}
|
||||||
|
provider={dataProvider}
|
||||||
|
fullHeight={false}
|
||||||
|
fixedInput={false}
|
||||||
|
>
|
||||||
|
<svelte:fragment slot="header">
|
||||||
|
<div class="mt-3">
|
||||||
|
<ThreadParentMessage {message} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if (message.replies ?? $messagesStore?.length ?? 0) > 0}
|
||||||
|
<div class="separator">
|
||||||
|
<div class="label lower">
|
||||||
|
<Label
|
||||||
|
label={activity.string.RepliesCount}
|
||||||
|
params={{ replies: message.replies ?? $messagesStore?.length ?? 1 }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="line" />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</svelte:fragment>
|
||||||
|
</ChannelScrollView>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.separator {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin: 0.5rem 0;
|
||||||
|
|
||||||
|
.label {
|
||||||
|
white-space: nowrap;
|
||||||
|
margin: 0 0.5rem;
|
||||||
|
color: var(--theme-halfcontent-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.line {
|
||||||
|
background: var(--theme-refinput-border);
|
||||||
|
height: 1px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -15,7 +15,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Doc, Ref } from '@hcengineering/core'
|
import { Doc, Ref } from '@hcengineering/core'
|
||||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||||
import { Breadcrumbs, Label, location as locationStore, Header, BreadcrumbItem } from '@hcengineering/ui'
|
import { Breadcrumbs, location as locationStore, Header, BreadcrumbItem, Loading } from '@hcengineering/ui'
|
||||||
import { createEventDispatcher, onDestroy } from 'svelte'
|
import { createEventDispatcher, onDestroy } from 'svelte'
|
||||||
import activity, { ActivityMessage, DisplayActivityMessage } from '@hcengineering/activity'
|
import activity, { ActivityMessage, DisplayActivityMessage } from '@hcengineering/activity'
|
||||||
import { getMessageFromLoc, messageInFocus } from '@hcengineering/activity-resources'
|
import { getMessageFromLoc, messageInFocus } from '@hcengineering/activity-resources'
|
||||||
@ -23,14 +23,14 @@
|
|||||||
import attachment from '@hcengineering/attachment'
|
import attachment from '@hcengineering/attachment'
|
||||||
|
|
||||||
import chunter from '../../plugin'
|
import chunter from '../../plugin'
|
||||||
import ThreadParentMessage from './ThreadParentPresenter.svelte'
|
|
||||||
import { getObjectIcon, getChannelName } from '../../utils'
|
import { getObjectIcon, getChannelName } from '../../utils'
|
||||||
import ChannelScrollView from '../ChannelScrollView.svelte'
|
import { threadMessagesStore } from '../../stores'
|
||||||
import { ChannelDataProvider } from '../../channelDataProvider'
|
import ThreadContent from './ThreadContent.svelte'
|
||||||
|
|
||||||
export let _id: Ref<ActivityMessage>
|
export let _id: Ref<ActivityMessage>
|
||||||
export let selectedMessageId: Ref<ActivityMessage> | undefined = undefined
|
export let selectedMessageId: Ref<ActivityMessage> | undefined = undefined
|
||||||
export let showHeader: boolean = true
|
export let showHeader: boolean = true
|
||||||
|
export let syncLocation = true
|
||||||
|
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
const hierarchy = client.getHierarchy()
|
const hierarchy = client.getHierarchy()
|
||||||
@ -40,12 +40,12 @@
|
|||||||
const channelQuery = createQuery()
|
const channelQuery = createQuery()
|
||||||
|
|
||||||
let channel: Doc | undefined = undefined
|
let channel: Doc | undefined = undefined
|
||||||
let message: DisplayActivityMessage | undefined = undefined
|
let message: DisplayActivityMessage | undefined = $threadMessagesStore?._id === _id ? $threadMessagesStore : undefined
|
||||||
|
let isLoading = true
|
||||||
let channelName: string | undefined = undefined
|
let channelName: string | undefined = undefined
|
||||||
let dataProvider: ChannelDataProvider | undefined = undefined
|
|
||||||
|
|
||||||
const unsubscribe = messageInFocus.subscribe((id) => {
|
const unsubscribe = messageInFocus.subscribe((id) => {
|
||||||
|
if (!syncLocation) return
|
||||||
if (id !== undefined && id !== selectedMessageId) {
|
if (id !== undefined && id !== selectedMessageId) {
|
||||||
selectedMessageId = id
|
selectedMessageId = id
|
||||||
}
|
}
|
||||||
@ -54,6 +54,7 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
const unsubscribeLocation = locationStore.subscribe((newLocation) => {
|
const unsubscribeLocation = locationStore.subscribe((newLocation) => {
|
||||||
|
if (!syncLocation) return
|
||||||
const id = getMessageFromLoc(newLocation)
|
const id = getMessageFromLoc(newLocation)
|
||||||
selectedMessageId = id
|
selectedMessageId = id
|
||||||
messageInFocus.set(id)
|
messageInFocus.set(id)
|
||||||
@ -64,12 +65,17 @@
|
|||||||
unsubscribeLocation()
|
unsubscribeLocation()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
$: if (message && message._id !== _id) {
|
||||||
|
message = $threadMessagesStore?._id === _id ? $threadMessagesStore : undefined
|
||||||
|
isLoading = message === undefined
|
||||||
|
}
|
||||||
|
|
||||||
$: messageQuery.query(
|
$: messageQuery.query(
|
||||||
activity.class.ActivityMessage,
|
activity.class.ActivityMessage,
|
||||||
{ _id },
|
{ _id },
|
||||||
(result: ActivityMessage[]) => {
|
(result: ActivityMessage[]) => {
|
||||||
message = result[0] as DisplayActivityMessage
|
message = result[0] as DisplayActivityMessage
|
||||||
|
isLoading = false
|
||||||
if (message === undefined) {
|
if (message === undefined) {
|
||||||
dispatch('close')
|
dispatch('close')
|
||||||
}
|
}
|
||||||
@ -88,42 +94,26 @@
|
|||||||
channel = res[0]
|
channel = res[0]
|
||||||
})
|
})
|
||||||
|
|
||||||
$: if (message !== undefined && dataProvider === undefined) {
|
|
||||||
dataProvider = new ChannelDataProvider(
|
|
||||||
undefined,
|
|
||||||
message.space,
|
|
||||||
message._id,
|
|
||||||
chunter.class.ThreadMessage,
|
|
||||||
selectedMessageId,
|
|
||||||
true
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
$: message &&
|
$: message &&
|
||||||
getChannelName(message.attachedTo, message.attachedToClass, channel).then((res) => {
|
getChannelName(message.attachedTo, message.attachedToClass, channel).then((res) => {
|
||||||
channelName = res
|
channelName = res
|
||||||
})
|
})
|
||||||
|
|
||||||
let breadcrumbs: BreadcrumbItem[] = []
|
let breadcrumbs: BreadcrumbItem[] = []
|
||||||
$: breadcrumbs = showHeader ? getBreadcrumbsItems(channel, message, channelName) : []
|
$: breadcrumbs = showHeader ? getBreadcrumbsItems(channel, channelName) : []
|
||||||
|
|
||||||
function getBreadcrumbsItems (
|
function getBreadcrumbsItems (channel?: Doc, channelName?: string): BreadcrumbItem[] {
|
||||||
channel?: Doc,
|
if (channel === undefined) {
|
||||||
message?: DisplayActivityMessage,
|
|
||||||
channelName?: string
|
|
||||||
): BreadcrumbItem[] {
|
|
||||||
if (message === undefined) {
|
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
const isPersonAvatar =
|
const isPersonAvatar =
|
||||||
message.attachedToClass === chunter.class.DirectMessage ||
|
channel._class === chunter.class.DirectMessage || hierarchy.isDerived(channel._class, contact.class.Person)
|
||||||
hierarchy.isDerived(message.attachedToClass, contact.class.Person)
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
id: 'channel',
|
id: 'channel',
|
||||||
icon: getObjectIcon(message.attachedToClass),
|
icon: getObjectIcon(channel._class),
|
||||||
iconProps: { value: channel },
|
iconProps: { value: channel },
|
||||||
iconWidth: isPersonAvatar ? 'auto' : undefined,
|
iconWidth: isPersonAvatar ? 'auto' : undefined,
|
||||||
withoutIconBackground: isPersonAvatar,
|
withoutIconBackground: isPersonAvatar,
|
||||||
@ -143,8 +133,6 @@
|
|||||||
|
|
||||||
dispatch('channel')
|
dispatch('channel')
|
||||||
}
|
}
|
||||||
|
|
||||||
$: messagesStore = dataProvider?.messagesStore
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if showHeader}
|
{#if showHeader}
|
||||||
@ -153,54 +141,10 @@
|
|||||||
</Header>
|
</Header>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div class="hulyComponent-content hulyComponent-content__container noShrink">
|
{#if message}
|
||||||
{#if message && dataProvider !== undefined}
|
{#key _id}
|
||||||
<ChannelScrollView
|
<ThreadContent bind:selectedMessageId {message} />
|
||||||
bind:selectedMessageId
|
{/key}
|
||||||
embedded
|
{:else if isLoading}
|
||||||
skipLabels
|
<Loading />
|
||||||
object={message}
|
|
||||||
provider={dataProvider}
|
|
||||||
fullHeight={false}
|
|
||||||
fixedInput={false}
|
|
||||||
>
|
|
||||||
<svelte:fragment slot="header">
|
|
||||||
<div class="mt-3">
|
|
||||||
<ThreadParentMessage {message} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{#if (message.replies ?? $messagesStore?.length ?? 0) > 0}
|
|
||||||
<div class="separator">
|
|
||||||
<div class="label lower">
|
|
||||||
<Label
|
|
||||||
label={activity.string.RepliesCount}
|
|
||||||
params={{ replies: message.replies ?? $messagesStore?.length ?? 1 }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="line" />
|
|
||||||
</div>
|
|
||||||
{/if}
|
{/if}
|
||||||
</svelte:fragment>
|
|
||||||
</ChannelScrollView>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.separator {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
margin: 0.5rem 0;
|
|
||||||
|
|
||||||
.label {
|
|
||||||
white-space: nowrap;
|
|
||||||
margin: 0 0.5rem;
|
|
||||||
color: var(--theme-halfcontent-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.line {
|
|
||||||
background: var(--theme-refinput-border);
|
|
||||||
height: 1px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
@ -28,6 +28,7 @@ import { get } from 'svelte/store'
|
|||||||
import { chatSpecials } from './components/chat/utils'
|
import { chatSpecials } from './components/chat/utils'
|
||||||
import { getChannelName, isThreadMessage } from './utils'
|
import { getChannelName, isThreadMessage } from './utils'
|
||||||
import chunter from './plugin'
|
import chunter from './plugin'
|
||||||
|
import { threadMessagesStore } from './stores'
|
||||||
|
|
||||||
export function openChannel (_id: string, _class: Ref<Class<Doc>>, thread?: Ref<ActivityMessage>): void {
|
export function openChannel (_id: string, _class: Ref<Class<Doc>>, thread?: Ref<ActivityMessage>): void {
|
||||||
const loc = getCurrentLocation()
|
const loc = getCurrentLocation()
|
||||||
@ -168,6 +169,8 @@ export async function replyToThread (message: ActivityMessage, e: Event): Promis
|
|||||||
const fromSidebar = isElementFromSidebar(e.target as HTMLElement)
|
const fromSidebar = isElementFromSidebar(e.target as HTMLElement)
|
||||||
const loc = getCurrentLocation()
|
const loc = getCurrentLocation()
|
||||||
|
|
||||||
|
threadMessagesStore.set(message)
|
||||||
|
|
||||||
if (fromSidebar) {
|
if (fromSidebar) {
|
||||||
const widget = getClient().getModel().findAllSync(workbench.class.Widget, { _id: chunter.ids.ChatWidget })[0]
|
const widget = getClient().getModel().findAllSync(workbench.class.Widget, { _id: chunter.ids.ChatWidget })[0]
|
||||||
const widgetState = get(sidebarStore).widgetsState.get(widget._id)
|
const widgetState = get(sidebarStore).widgetsState.get(widget._id)
|
||||||
@ -235,7 +238,8 @@ export async function openChannelInSidebar (
|
|||||||
_class: Ref<Class<Doc>>,
|
_class: Ref<Class<Doc>>,
|
||||||
doc?: Doc,
|
doc?: Doc,
|
||||||
thread?: Ref<ActivityMessage>,
|
thread?: Ref<ActivityMessage>,
|
||||||
newTab = true
|
newTab = true,
|
||||||
|
selectedMessageId?: Ref<ActivityMessage>
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
|
|
||||||
@ -267,6 +271,7 @@ export async function openChannelInSidebar (
|
|||||||
_id,
|
_id,
|
||||||
_class,
|
_class,
|
||||||
thread,
|
thread,
|
||||||
|
selectedMessageId,
|
||||||
channelName: name
|
channelName: name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,11 +17,14 @@ import { writable } from 'svelte/store'
|
|||||||
import { type ChatMessage } from '@hcengineering/chunter'
|
import { type ChatMessage } from '@hcengineering/chunter'
|
||||||
import { type Markup, type Ref } from '@hcengineering/core'
|
import { type Markup, type Ref } from '@hcengineering/core'
|
||||||
import { languageStore } from '@hcengineering/ui'
|
import { languageStore } from '@hcengineering/ui'
|
||||||
|
import { type ActivityMessage } from '@hcengineering/activity'
|
||||||
|
|
||||||
export const translatingMessagesStore = writable<Set<Ref<ChatMessage>>>(new Set())
|
export const translatingMessagesStore = writable<Set<Ref<ChatMessage>>>(new Set())
|
||||||
export const translatedMessagesStore = writable<Map<Ref<ChatMessage>, Markup>>(new Map())
|
export const translatedMessagesStore = writable<Map<Ref<ChatMessage>, Markup>>(new Map())
|
||||||
export const shownTranslatedMessagesStore = writable<Set<Ref<ChatMessage>>>(new Set())
|
export const shownTranslatedMessagesStore = writable<Set<Ref<ChatMessage>>>(new Set())
|
||||||
|
|
||||||
|
export const threadMessagesStore = writable<ActivityMessage | undefined>(undefined)
|
||||||
|
|
||||||
languageStore.subscribe(() => {
|
languageStore.subscribe(() => {
|
||||||
translatedMessagesStore.set(new Map())
|
translatedMessagesStore.set(new Map())
|
||||||
shownTranslatedMessagesStore.set(new Set())
|
shownTranslatedMessagesStore.set(new Set())
|
||||||
|
@ -100,7 +100,13 @@ export interface InlineButton extends AttachedDoc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ChatWidgetTab extends WidgetTab {
|
export interface ChatWidgetTab extends WidgetTab {
|
||||||
data: { _id?: Ref<Doc>, _class?: Ref<Class<Doc>>, thread?: Ref<ActivityMessage>, channelName: string }
|
data: {
|
||||||
|
_id?: Ref<Doc>
|
||||||
|
_class?: Ref<Class<Doc>>
|
||||||
|
thread?: Ref<ActivityMessage>
|
||||||
|
channelName: string
|
||||||
|
selectedMessageId?: Ref<ActivityMessage>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -234,7 +240,14 @@ export default plugin(chunterId, {
|
|||||||
CanTranslateMessage: '' as Resource<(doc?: Doc | Doc[]) => Promise<boolean>>,
|
CanTranslateMessage: '' as Resource<(doc?: Doc | Doc[]) => Promise<boolean>>,
|
||||||
OpenThreadInSidebar: '' as Resource<(_id: Ref<ActivityMessage>, msg?: ActivityMessage, doc?: Doc) => Promise<void>>,
|
OpenThreadInSidebar: '' as Resource<(_id: Ref<ActivityMessage>, msg?: ActivityMessage, doc?: Doc) => Promise<void>>,
|
||||||
OpenChannelInSidebar: '' as Resource<
|
OpenChannelInSidebar: '' as Resource<
|
||||||
(_id: Ref<Doc>, _class: Ref<Doc>, doc?: Doc, thread?: Ref<ActivityMessage>) => Promise<void>
|
(
|
||||||
|
_id: Ref<Doc>,
|
||||||
|
_class: Ref<Class<Doc>>,
|
||||||
|
doc?: Doc,
|
||||||
|
thread?: Ref<ActivityMessage>,
|
||||||
|
newTab?: boolean,
|
||||||
|
selectedMessageId?: Ref<ActivityMessage>
|
||||||
|
) => Promise<void>
|
||||||
>
|
>
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -64,6 +64,7 @@
|
|||||||
|
|
||||||
$: if (object !== undefined && object?._id !== value.objectId) {
|
$: if (object !== undefined && object?._id !== value.objectId) {
|
||||||
object = undefined
|
object = undefined
|
||||||
|
isLoading = true
|
||||||
}
|
}
|
||||||
|
|
||||||
let isActionMenuOpened = false
|
let isActionMenuOpened = false
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { PersonAccount } from '@hcengineering/contact'
|
import { PersonAccount } from '@hcengineering/contact'
|
||||||
import { Avatar, personAccountByIdStore, personByIdStore } from '@hcengineering/contact-resources'
|
import { Avatar, personAccountByIdStore, personByIdStore } from '@hcengineering/contact-resources'
|
||||||
import { Ref } from '@hcengineering/core'
|
import { Class, Doc, Ref } from '@hcengineering/core'
|
||||||
import { BrowserNotification } from '@hcengineering/notification'
|
import { BrowserNotification } from '@hcengineering/notification'
|
||||||
import { Button, navigate, Notification as PlatformNotification, NotificationToast } from '@hcengineering/ui'
|
import { Button, navigate, Notification as PlatformNotification, NotificationToast } from '@hcengineering/ui'
|
||||||
import view, { decodeObjectURI } from '@hcengineering/view'
|
import view from '@hcengineering/view'
|
||||||
import chunter from '@hcengineering/chunter'
|
import chunter, { ThreadMessage } from '@hcengineering/chunter'
|
||||||
import { getResource } from '@hcengineering/platform'
|
import { getResource } from '@hcengineering/platform'
|
||||||
import { ActivityMessage } from '@hcengineering/activity'
|
import activity, { ActivityMessage } from '@hcengineering/activity'
|
||||||
|
import { getClient } from '@hcengineering/presentation'
|
||||||
|
|
||||||
import { pushAvailable, subscribePush } from '../utils'
|
import { pushAvailable, subscribePush } from '../utils'
|
||||||
import plugin from '../plugin'
|
import plugin from '../plugin'
|
||||||
@ -15,6 +16,9 @@
|
|||||||
export let notification: PlatformNotification
|
export let notification: PlatformNotification
|
||||||
export let onRemove: () => void
|
export let onRemove: () => void
|
||||||
|
|
||||||
|
const client = getClient()
|
||||||
|
const hierarchy = client.getHierarchy()
|
||||||
|
|
||||||
$: value = notification.params?.value as BrowserNotification
|
$: value = notification.params?.value as BrowserNotification
|
||||||
|
|
||||||
$: senderAccount =
|
$: senderAccount =
|
||||||
@ -24,18 +28,35 @@
|
|||||||
async function openChannelInSidebar (): Promise<void> {
|
async function openChannelInSidebar (): Promise<void> {
|
||||||
if (!value.onClickLocation) return
|
if (!value.onClickLocation) return
|
||||||
const { onClickLocation } = value
|
const { onClickLocation } = value
|
||||||
const [_id, _class] = decodeObjectURI(onClickLocation.path[3] ?? '')
|
let _id: Ref<Doc> | undefined = value.objectId
|
||||||
|
let _class: Ref<Class<Doc>> | undefined = value.objectClass
|
||||||
|
let thread = onClickLocation.path[4] as Ref<ActivityMessage> | undefined
|
||||||
|
const selectedMessageId: Ref<ActivityMessage> | undefined = value.messageId
|
||||||
|
|
||||||
|
if (_class && _id && hierarchy.isDerived(_class, activity.class.ActivityMessage)) {
|
||||||
|
const message = await client.findOne<ActivityMessage>(_class, { _id: _id as Ref<ActivityMessage> })
|
||||||
|
|
||||||
|
if (hierarchy.isDerived(_class, chunter.class.ThreadMessage)) {
|
||||||
|
const threadMessage = message as ThreadMessage
|
||||||
|
_id = threadMessage?.objectId
|
||||||
|
_class = threadMessage?.objectClass
|
||||||
|
thread = threadMessage?.attachedTo
|
||||||
|
} else {
|
||||||
|
_id = message?.attachedTo
|
||||||
|
_class = message?.attachedToClass
|
||||||
|
thread = (message?.replies ?? 0) > 0 ? message?._id : undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onRemove()
|
onRemove()
|
||||||
|
|
||||||
if (!_id || !_class || _id === '' || _class === '') {
|
if (!_id || !_class || _id === '' || _class === '' || selectedMessageId === undefined) {
|
||||||
navigate(onClickLocation)
|
navigate(onClickLocation)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const thread = onClickLocation.path[4] as Ref<ActivityMessage> | undefined
|
|
||||||
const fn = await getResource(chunter.function.OpenChannelInSidebar)
|
const fn = await getResource(chunter.function.OpenChannelInSidebar)
|
||||||
await fn(_id, _class, undefined, thread)
|
await fn(_id, _class, undefined, thread, true, selectedMessageId)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -56,7 +77,7 @@
|
|||||||
<Button
|
<Button
|
||||||
label={view.string.Open}
|
label={view.string.Open}
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
openChannelInSidebar()
|
void openChannelInSidebar()
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -53,6 +53,10 @@ export interface BrowserNotification extends Doc {
|
|||||||
onClickLocation?: Location
|
onClickLocation?: Location
|
||||||
senderId?: Ref<Account>
|
senderId?: Ref<Account>
|
||||||
tag: Ref<Doc>
|
tag: Ref<Doc>
|
||||||
|
messageId?: Ref<ActivityMessage>
|
||||||
|
messageClass?: Ref<Class<ActivityMessage>>
|
||||||
|
objectId: Ref<Doc>
|
||||||
|
objectClass: Ref<Class<Doc>>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PushData {
|
export interface PushData {
|
||||||
|
@ -0,0 +1,88 @@
|
|||||||
|
//
|
||||||
|
// Copyright © 2024 Hardcore Engineering Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License. You may
|
||||||
|
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
//
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import { type Editor } from '@tiptap/core'
|
||||||
|
import ListKeymap, { type ListKeymapOptions, listHelpers } from '@tiptap/extension-list-keymap'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Workaround for the original ListKeymap extension issue that
|
||||||
|
* https://github.com/ueberdosis/tiptap/issues/4368
|
||||||
|
*/
|
||||||
|
export const ListKeymapExtension = ListKeymap.extend<ListKeymapOptions>({
|
||||||
|
addKeyboardShortcuts () {
|
||||||
|
const handleBackspace = (editor: Editor): boolean => {
|
||||||
|
let handled = false
|
||||||
|
|
||||||
|
if (!editor.state.selection.empty) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
this.options.listTypes.forEach(({ itemName, wrapperNames }) => {
|
||||||
|
if (editor.state.schema.nodes[itemName] === undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (listHelpers.handleBackspace(editor, itemName, wrapperNames)) {
|
||||||
|
handled = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return handled
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDelete = (editor: Editor): boolean => {
|
||||||
|
let handled = false
|
||||||
|
|
||||||
|
if (!editor.state.selection.empty) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
this.options.listTypes.forEach(({ itemName }) => {
|
||||||
|
if (editor.state.schema.nodes[itemName] === undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (listHelpers.handleDelete(editor, itemName)) {
|
||||||
|
handled = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return handled
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleBackspaceSafe = (editor: Editor): boolean => {
|
||||||
|
try {
|
||||||
|
return handleBackspace(editor)
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDeleteSafe = (editor: Editor): boolean => {
|
||||||
|
try {
|
||||||
|
return handleDelete(editor)
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
Backspace: ({ editor }) => handleBackspaceSafe(editor),
|
||||||
|
'Mod-Backspace': ({ editor }) => handleBackspaceSafe(editor),
|
||||||
|
Delete: ({ editor }) => handleDeleteSafe(editor),
|
||||||
|
'Mod-Delete': ({ editor }) => handleDeleteSafe(editor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
@ -19,7 +19,6 @@ import { CodeExtension, codeOptions } from '@hcengineering/text'
|
|||||||
import textEditor, { type ActionContext, type ExtensionCreator, type TextEditorMode } from '@hcengineering/text-editor'
|
import textEditor, { type ActionContext, type ExtensionCreator, type TextEditorMode } from '@hcengineering/text-editor'
|
||||||
import { type AnyExtension, type Editor, Extension } from '@tiptap/core'
|
import { type AnyExtension, type Editor, Extension } from '@tiptap/core'
|
||||||
import { type Level } from '@tiptap/extension-heading'
|
import { type Level } from '@tiptap/extension-heading'
|
||||||
import ListKeymap from '@tiptap/extension-list-keymap'
|
|
||||||
import TableHeader from '@tiptap/extension-table-header'
|
import TableHeader from '@tiptap/extension-table-header'
|
||||||
import 'prosemirror-codemark/dist/codemark.css'
|
import 'prosemirror-codemark/dist/codemark.css'
|
||||||
|
|
||||||
@ -30,6 +29,7 @@ import { FileExtension, type FileOptions } from '../components/extension/fileExt
|
|||||||
import { HardBreakExtension } from '../components/extension/hardBreak'
|
import { HardBreakExtension } from '../components/extension/hardBreak'
|
||||||
import { ImageExtension, type ImageOptions } from '../components/extension/imageExt'
|
import { ImageExtension, type ImageOptions } from '../components/extension/imageExt'
|
||||||
import { InlineToolbarExtension } from '../components/extension/inlineToolbar'
|
import { InlineToolbarExtension } from '../components/extension/inlineToolbar'
|
||||||
|
import { ListKeymapExtension } from '../components/extension/listkeymap'
|
||||||
import { NodeUuidExtension } from '../components/extension/nodeUuid'
|
import { NodeUuidExtension } from '../components/extension/nodeUuid'
|
||||||
import { ParagraphExtension } from '../components/extension/paragraph'
|
import { ParagraphExtension } from '../components/extension/paragraph'
|
||||||
import { SubmitExtension, type SubmitOptions } from '../components/extension/submit'
|
import { SubmitExtension, type SubmitOptions } from '../components/extension/submit'
|
||||||
@ -195,7 +195,7 @@ async function buildEditorKit (): Promise<Extension<EditorKitOptions, any>> {
|
|||||||
|
|
||||||
staticKitExtensions.push([
|
staticKitExtensions.push([
|
||||||
500,
|
500,
|
||||||
ListKeymap.configure({
|
ListKeymapExtension.configure({
|
||||||
listTypes: [
|
listTypes: [
|
||||||
{
|
{
|
||||||
itemName: 'listItem',
|
itemName: 'listItem',
|
||||||
|
@ -74,17 +74,16 @@
|
|||||||
on:change={(e) => change(e, slot)}
|
on:change={(e) => change(e, slot)}
|
||||||
on:dueChange={(e) => dueChange(e, slot)}
|
on:dueChange={(e) => dueChange(e, slot)}
|
||||||
/>
|
/>
|
||||||
<div class="tool flex-no-shrink">
|
|
||||||
<ButtonIcon
|
<ButtonIcon
|
||||||
kind="tertiary"
|
kind="tertiary"
|
||||||
size="small"
|
size="small"
|
||||||
icon={IconDelete}
|
icon={IconDelete}
|
||||||
|
dataId={'btnDelete'}
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
dispatch('remove', { _id: slot._id })
|
dispatch('remove', { _id: slot._id })
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
{/each}
|
{/each}
|
||||||
</Scroller>
|
</Scroller>
|
||||||
<div class="flex-row-center flex-gap-4">
|
<div class="flex-row-center flex-gap-4">
|
||||||
|
@ -160,6 +160,7 @@ export default plugin(timeId, {
|
|||||||
CreatedToDo: '' as IntlString,
|
CreatedToDo: '' as IntlString,
|
||||||
AddToDo: '' as IntlString,
|
AddToDo: '' as IntlString,
|
||||||
NewToDoDetails: '' as IntlString,
|
NewToDoDetails: '' as IntlString,
|
||||||
ToDo: '' as IntlString
|
ToDo: '' as IntlString,
|
||||||
|
NewToDo: '' as IntlString
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -316,3 +316,20 @@ export function minimizeSidebar (closedByUser = false): void {
|
|||||||
|
|
||||||
sidebarStore.set({ ...state, ...widgetsState, widget: undefined, variant: SidebarVariant.MINI })
|
sidebarStore.set({ ...state, ...widgetsState, widget: undefined, variant: SidebarVariant.MINI })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function updateTabData (widget: Ref<Widget>, tabId: string, data: Record<string, any>): void {
|
||||||
|
const state = get(sidebarStore)
|
||||||
|
const { widgetsState } = state
|
||||||
|
const widgetState = widgetsState.get(widget)
|
||||||
|
|
||||||
|
if (widgetState === undefined) return
|
||||||
|
|
||||||
|
const tabs = widgetState.tabs.map((it) => (it.id === tabId ? { ...it, data: { ...it.data, ...data } } : it))
|
||||||
|
|
||||||
|
widgetsState.set(widget, { ...widgetState, tabs })
|
||||||
|
|
||||||
|
sidebarStore.set({
|
||||||
|
...state,
|
||||||
|
widgetsState
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -175,7 +175,8 @@ export async function getCommonNotificationTxes (
|
|||||||
doc,
|
doc,
|
||||||
receiver,
|
receiver,
|
||||||
sender,
|
sender,
|
||||||
subscriptions
|
subscriptions,
|
||||||
|
_class
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -487,6 +488,14 @@ export async function getTranslatedNotificationContent (
|
|||||||
return { title: '', body: '' }
|
return { title: '', body: '' }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isReactionMessage (message?: ActivityMessage): boolean {
|
||||||
|
return (
|
||||||
|
message !== undefined &&
|
||||||
|
message._class === activity.class.DocUpdateMessage &&
|
||||||
|
(message as DocUpdateMessage).objectClass === activity.class.Reaction
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export async function createPushFromInbox (
|
export async function createPushFromInbox (
|
||||||
control: TriggerControl,
|
control: TriggerControl,
|
||||||
receiver: ReceiverInfo,
|
receiver: ReceiverInfo,
|
||||||
@ -497,10 +506,9 @@ export async function createPushFromInbox (
|
|||||||
sender: SenderInfo,
|
sender: SenderInfo,
|
||||||
_id: Ref<Doc>,
|
_id: Ref<Doc>,
|
||||||
subscriptions: PushSubscription[],
|
subscriptions: PushSubscription[],
|
||||||
cache: Map<Ref<Doc>, Doc> = new Map<Ref<Doc>, Doc>()
|
message?: ActivityMessage
|
||||||
): Promise<Tx | undefined> {
|
): Promise<Tx | undefined> {
|
||||||
let { title, body } = await getTranslatedNotificationContent(data, _class, control)
|
let { title, body } = await getTranslatedNotificationContent(data, _class, control)
|
||||||
|
|
||||||
if (title === '' || body === '') {
|
if (title === '' || body === '') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -515,13 +523,12 @@ export async function createPushFromInbox (
|
|||||||
|
|
||||||
if (provider !== undefined) {
|
if (provider !== undefined) {
|
||||||
const encodeFn = await getResource(provider.encode)
|
const encodeFn = await getResource(provider.encode)
|
||||||
const doc = cache.get(attachedTo) ?? (await control.findAll(control.ctx, attachedToClass, { _id: attachedTo }))[0]
|
const doc = (await control.findAll(control.ctx, attachedToClass, { _id: attachedTo }))[0]
|
||||||
|
|
||||||
if (doc === undefined) {
|
if (doc === undefined) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cache.set(doc._id, doc)
|
|
||||||
id = await encodeFn(doc, control)
|
id = await encodeFn(doc, control)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -543,6 +550,12 @@ export async function createPushFromInbox (
|
|||||||
body,
|
body,
|
||||||
senderId: sender._id,
|
senderId: sender._id,
|
||||||
tag: _id,
|
tag: _id,
|
||||||
|
objectId: attachedTo,
|
||||||
|
objectClass: attachedToClass,
|
||||||
|
messageId: isReactionMessage(message) ? (message?.attachedTo as Ref<ActivityMessage>) : message?._id,
|
||||||
|
messageClass: isReactionMessage(message)
|
||||||
|
? (message?.attachedToClass as Ref<Class<ActivityMessage>>)
|
||||||
|
: message?._class,
|
||||||
onClickLocation: {
|
onClickLocation: {
|
||||||
path
|
path
|
||||||
}
|
}
|
||||||
@ -664,6 +677,7 @@ export async function applyNotificationProviders (
|
|||||||
receiver: ReceiverInfo,
|
receiver: ReceiverInfo,
|
||||||
sender: SenderInfo,
|
sender: SenderInfo,
|
||||||
subscriptions: PushSubscription[],
|
subscriptions: PushSubscription[],
|
||||||
|
_class = notification.class.ActivityInboxNotification,
|
||||||
message?: ActivityMessage
|
message?: ActivityMessage
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const resources = control.modelDb.findAllSync(serverNotification.class.NotificationProviderResources, {})
|
const resources = control.modelDb.findAllSync(serverNotification.class.NotificationProviderResources, {})
|
||||||
@ -676,10 +690,11 @@ export async function applyNotificationProviders (
|
|||||||
attachedTo,
|
attachedTo,
|
||||||
attachedToClass,
|
attachedToClass,
|
||||||
data,
|
data,
|
||||||
notification.class.ActivityInboxNotification,
|
_class,
|
||||||
sender,
|
sender,
|
||||||
data._id,
|
data._id,
|
||||||
subscriptions
|
subscriptions,
|
||||||
|
message
|
||||||
)
|
)
|
||||||
if (pushTx !== undefined) {
|
if (pushTx !== undefined) {
|
||||||
res.push(pushTx)
|
res.push(pushTx)
|
||||||
@ -796,6 +811,7 @@ export async function getNotificationTxes (
|
|||||||
receiver,
|
receiver,
|
||||||
sender,
|
sender,
|
||||||
subscriptions,
|
subscriptions,
|
||||||
|
notificationData._class,
|
||||||
message
|
message
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -172,6 +172,8 @@
|
|||||||
"@hcengineering/github": "^0.6.0",
|
"@hcengineering/github": "^0.6.0",
|
||||||
"@hcengineering/github-assets": "^0.6.0",
|
"@hcengineering/github-assets": "^0.6.0",
|
||||||
"@hcengineering/server-ai-bot": "^0.6.0",
|
"@hcengineering/server-ai-bot": "^0.6.0",
|
||||||
"@hcengineering/server-ai-bot-resources": "^0.6.0"
|
"@hcengineering/server-ai-bot-resources": "^0.6.0",
|
||||||
|
"@hcengineering/time": "^0.6.0",
|
||||||
|
"@hcengineering/time-assets": "^0.6.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ import { trackerId } from '@hcengineering/tracker'
|
|||||||
import { trainingId } from '@hcengineering/training'
|
import { trainingId } from '@hcengineering/training'
|
||||||
import { viewId } from '@hcengineering/view'
|
import { viewId } from '@hcengineering/view'
|
||||||
import { workbenchId } from '@hcengineering/workbench'
|
import { workbenchId } from '@hcengineering/workbench'
|
||||||
|
import { timeId } from '@hcengineering/time'
|
||||||
import coreEng from '@hcengineering/core/lang/en.json'
|
import coreEng from '@hcengineering/core/lang/en.json'
|
||||||
import loginEng from '@hcengineering/login-assets/lang/en.json'
|
import loginEng from '@hcengineering/login-assets/lang/en.json'
|
||||||
import platformEng from '@hcengineering/platform/lang/en.json'
|
import platformEng from '@hcengineering/platform/lang/en.json'
|
||||||
@ -68,6 +69,7 @@ import trackerEn from '@hcengineering/tracker-assets/lang/en.json'
|
|||||||
import trainingEn from '@hcengineering/training-assets/lang/en.json'
|
import trainingEn from '@hcengineering/training-assets/lang/en.json'
|
||||||
import viewEn from '@hcengineering/view-assets/lang/en.json'
|
import viewEn from '@hcengineering/view-assets/lang/en.json'
|
||||||
import workbenchEn from '@hcengineering/workbench-assets/lang/en.json'
|
import workbenchEn from '@hcengineering/workbench-assets/lang/en.json'
|
||||||
|
import timeEn from '@hcengineering/time-assets/lang/en.json'
|
||||||
|
|
||||||
export function registerStringLoaders (): void {
|
export function registerStringLoaders (): void {
|
||||||
addStringsLoader(coreId, async (lang: string) => coreEng)
|
addStringsLoader(coreId, async (lang: string) => coreEng)
|
||||||
@ -106,4 +108,5 @@ export function registerStringLoaders (): void {
|
|||||||
addStringsLoader(productsId, async (lang: string) => productsEn)
|
addStringsLoader(productsId, async (lang: string) => productsEn)
|
||||||
addStringsLoader(trainingId, async (lang: string) => trainingEn)
|
addStringsLoader(trainingId, async (lang: string) => trainingEn)
|
||||||
addStringsLoader(githubId, async (lang: string) => githubEn)
|
addStringsLoader(githubId, async (lang: string) => githubEn)
|
||||||
|
addStringsLoader(timeId, async (lang: string) => timeEn)
|
||||||
}
|
}
|
||||||
|
@ -24,10 +24,10 @@ export async function onAuthorize (login?: string): Promise<void> {
|
|||||||
)
|
)
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
|
|
||||||
const config = await client.findOne(github.class.GithubAuthentication, {})
|
// Remove old authorizations.
|
||||||
|
const config = await client.findAll(github.class.GithubAuthentication, {})
|
||||||
if (config !== undefined) {
|
for (const c of config) {
|
||||||
await client.remove(config)
|
await client.remove(c)
|
||||||
}
|
}
|
||||||
await client.createDoc<GithubAuthentication>(github.class.GithubAuthentication, core.space.Workspace, {
|
await client.createDoc<GithubAuthentication>(github.class.GithubAuthentication, core.space.Workspace, {
|
||||||
attachedTo: meId,
|
attachedTo: meId,
|
||||||
|
@ -59,7 +59,7 @@ export class PlanningPage extends CalendarPage {
|
|||||||
readonly textPanelToDoDescription = (): Locator => this.panel().locator('div.top-content div.tiptap > p')
|
readonly textPanelToDoDescription = (): Locator => this.panel().locator('div.top-content div.tiptap > p')
|
||||||
readonly textPanelDueDate = (): Locator =>
|
readonly textPanelDueDate = (): Locator =>
|
||||||
this.panel().locator(
|
this.panel().locator(
|
||||||
'div.slots-content div.flex-row-top.justify-between div.flex-row-center button:first-child span'
|
'div.slots-content div.flex-row-top.justify-between div.flex-row-center .hulyButton:first-child span'
|
||||||
)
|
)
|
||||||
|
|
||||||
readonly textPanelPriority = (): Locator => this.panel().locator('button#priorityButton svg')
|
readonly textPanelPriority = (): Locator => this.panel().locator('button#priorityButton svg')
|
||||||
@ -189,7 +189,7 @@ export class PlanningPage extends CalendarPage {
|
|||||||
const row = this.page.locator(p).nth(rowNumber)
|
const row = this.page.locator(p).nth(rowNumber)
|
||||||
|
|
||||||
// dateStart
|
// dateStart
|
||||||
await row.locator('div.dateEditor-container:first-child > div.min-w-28:first-child button').click()
|
await row.locator('div.dateEditor-container:first-child > div.min-w-28:first-child .hulyButton').click()
|
||||||
if (slot.dateStart === 'today') {
|
if (slot.dateStart === 'today') {
|
||||||
await this.buttonCalendarToday().click()
|
await this.buttonCalendarToday().click()
|
||||||
} else {
|
} else {
|
||||||
@ -204,21 +204,17 @@ export class PlanningPage extends CalendarPage {
|
|||||||
// timeStart
|
// timeStart
|
||||||
const hours = slot.timeStart.substring(0, 2)
|
const hours = slot.timeStart.substring(0, 2)
|
||||||
const minutes = slot.timeStart.substring(2, slot.timeStart.length)
|
const minutes = slot.timeStart.substring(2, slot.timeStart.length)
|
||||||
|
await row.locator('div.dateEditor-container:nth-child(1) .hulyButton span.digit:first-child').focus()
|
||||||
await row
|
await row
|
||||||
.locator('div.dateEditor-container:nth-child(1) button:last-child span.digit:first-child')
|
.locator('div.dateEditor-container:nth-child(1) .hulyButton span.digit:first-child')
|
||||||
.click({ delay: 200 })
|
|
||||||
await row
|
|
||||||
.locator('div.dateEditor-container:nth-child(1) button:last-child span.digit:first-child')
|
|
||||||
.pressSequentially(hours, { delay: 100 })
|
.pressSequentially(hours, { delay: 100 })
|
||||||
|
await row.locator('div.dateEditor-container:nth-child(1) .hulyButton span.digit:last-child').focus()
|
||||||
await row
|
await row
|
||||||
.locator('div.dateEditor-container:nth-child(1) button:last-child span.digit:last-child')
|
.locator('div.dateEditor-container:nth-child(1) .hulyButton span.digit:last-child')
|
||||||
.click({ delay: 200 })
|
|
||||||
await row
|
|
||||||
.locator('div.dateEditor-container:nth-child(1) button:last-child span.digit:last-child')
|
|
||||||
.pressSequentially(minutes, { delay: 100 })
|
.pressSequentially(minutes, { delay: 100 })
|
||||||
|
|
||||||
// dateEnd + timeEnd
|
// dateEnd + timeEnd
|
||||||
await row.locator('div.dateEditor-container.difference button').click()
|
await row.locator('div.dateEditor-container.difference .hulyButton').click()
|
||||||
await this.fillSelectDatePopup(slot.dateEnd.day, slot.dateEnd.month, slot.dateEnd.year, slot.timeEnd)
|
await this.fillSelectDatePopup(slot.dateEnd.day, slot.dateEnd.month, slot.dateEnd.year, slot.timeEnd)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,11 +224,13 @@ export class PlanningPage extends CalendarPage {
|
|||||||
: 'div.hulyModal-container div.slots-content div.scroller-container div.box div.flex-between.min-w-full'
|
: 'div.hulyModal-container div.slots-content div.scroller-container div.box div.flex-between.min-w-full'
|
||||||
const row = this.page.locator(p).nth(rowNumber)
|
const row = this.page.locator(p).nth(rowNumber)
|
||||||
// timeStart
|
// timeStart
|
||||||
await expect(row.locator('div.dateEditor-container:nth-child(1) button:last-child div.datetime-input')).toHaveText(
|
await expect(
|
||||||
slot.timeStart
|
row.locator('div.dateEditor-container:nth-child(1) .hulyButton:last-child div.datetime-input')
|
||||||
)
|
).toHaveText(slot.timeStart)
|
||||||
// timeEnd
|
// timeEnd
|
||||||
await expect(row.locator('div.dateEditor-container.difference button > div:first-child')).toHaveText(slot.timeEnd)
|
await expect(row.locator('div.dateEditor-container.difference .hulyButton > div:first-child')).toHaveText(
|
||||||
|
slot.timeEnd
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async openToDoByName (toDoName: string): Promise<void> {
|
async openToDoByName (toDoName: string): Promise<void> {
|
||||||
@ -304,11 +302,10 @@ export class PlanningPage extends CalendarPage {
|
|||||||
public async deleteTimeSlot (rowNumber: number): Promise<void> {
|
public async deleteTimeSlot (rowNumber: number): Promise<void> {
|
||||||
const row = this.page
|
const row = this.page
|
||||||
.locator(
|
.locator(
|
||||||
'div.hulyModal-container div.slots-content div.scroller-container div.box div.flex-between.min-w-full div.tool'
|
'div.hulyModal-container div.slots-content div.scroller-container div.box div.flex-between.min-w-full button[data-id="btnDelete"]'
|
||||||
)
|
)
|
||||||
.nth(rowNumber)
|
.nth(rowNumber)
|
||||||
await row.locator('xpath=..').hover()
|
await row.click()
|
||||||
await row.locator('button').click()
|
|
||||||
await this.pressYesDeletePopup(this.page)
|
await this.pressYesDeletePopup(this.page)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,8 +314,8 @@ export class PlanningPage extends CalendarPage {
|
|||||||
.locator('div.hulyModal-container div.slots-content div.scroller-container div.box div.flex-between.min-w-full')
|
.locator('div.hulyModal-container div.slots-content div.scroller-container div.box div.flex-between.min-w-full')
|
||||||
.nth(rowNumber)
|
.nth(rowNumber)
|
||||||
// dateEnd
|
// dateEnd
|
||||||
await expect(row.locator('div.dateEditor-container:first-child > div.min-w-28:first-child button')).toContainText(
|
await expect(
|
||||||
dateEnd
|
row.locator('div.dateEditor-container:first-child > div.min-w-28:first-child .hulyButton')
|
||||||
)
|
).toContainText(dateEnd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user