mirror of
https://github.com/hcengineering/platform.git
synced 2024-11-21 16:09:12 +03:00
Fix meeting minutes (#7181)
Some checks are pending
CI / build (push) Waiting to run
CI / svelte-check (push) Blocked by required conditions
CI / formatting (push) Blocked by required conditions
CI / test (push) Blocked by required conditions
CI / uitest (push) Waiting to run
CI / uitest-pg (push) Waiting to run
CI / uitest-qms (push) Waiting to run
CI / docker-build (push) Blocked by required conditions
CI / dist-build (push) Blocked by required conditions
Some checks are pending
CI / build (push) Waiting to run
CI / svelte-check (push) Blocked by required conditions
CI / formatting (push) Blocked by required conditions
CI / test (push) Blocked by required conditions
CI / uitest (push) Waiting to run
CI / uitest-pg (push) Waiting to run
CI / uitest-qms (push) Waiting to run
CI / docker-build (push) Blocked by required conditions
CI / dist-build (push) Blocked by required conditions
Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com>
This commit is contained in:
parent
430be8c3ba
commit
bcdfed6871
@ -201,11 +201,8 @@ export class TDocUpdateMessageViewlet extends TDoc implements DocUpdateMessageVi
|
|||||||
|
|
||||||
@Model(activity.class.ActivityExtension, core.class.Doc, DOMAIN_MODEL)
|
@Model(activity.class.ActivityExtension, core.class.Doc, DOMAIN_MODEL)
|
||||||
export class TActivityExtension extends TDoc implements ActivityExtension {
|
export class TActivityExtension extends TDoc implements ActivityExtension {
|
||||||
@Prop(TypeRef(core.class.Class), core.string.Class)
|
ofClass!: Ref<Class<Doc>>
|
||||||
@Index(IndexKind.Indexed)
|
components!: Record<ActivityExtensionKind, { component: AnyComponent, props?: Record<string, any> }>
|
||||||
ofClass!: Ref<Class<Doc>>
|
|
||||||
|
|
||||||
components!: Record<ActivityExtensionKind, AnyComponent>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Model(activity.class.ActivityMessagesFilter, core.class.Doc, DOMAIN_MODEL)
|
@Model(activity.class.ActivityMessagesFilter, core.class.Doc, DOMAIN_MODEL)
|
||||||
|
@ -85,7 +85,7 @@ export function createModel (builder: Builder): void {
|
|||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: analyticsCollector.class.OnboardingChannel,
|
ofClass: analyticsCollector.class.OnboardingChannel,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.createDoc<ActivityMessageControl<OnboardingChannel>>(
|
builder.createDoc<ActivityMessageControl<OnboardingChannel>>(
|
||||||
|
@ -273,27 +273,27 @@ export function createModel (builder: Builder): void {
|
|||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: chunter.class.Channel,
|
ofClass: chunter.class.Channel,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: chunter.class.DirectMessage,
|
ofClass: chunter.class.DirectMessage,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: activity.class.DocUpdateMessage,
|
ofClass: activity.class.DocUpdateMessage,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: chunter.class.ChatMessage,
|
ofClass: chunter.class.ChatMessage,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: activity.class.ActivityReference,
|
ofClass: activity.class.ActivityReference,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
// Indexing
|
// Indexing
|
||||||
|
@ -263,22 +263,22 @@ export function createModel (builder: Builder): void {
|
|||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: contact.class.Contact,
|
ofClass: contact.class.Contact,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: contact.class.Person,
|
ofClass: contact.class.Person,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: contact.class.Organization,
|
ofClass: contact.class.Organization,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: contact.class.Member,
|
ofClass: contact.class.Member,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.mixin(contact.mixin.Employee, core.class.Class, view.mixin.ObjectFactory, {
|
builder.mixin(contact.mixin.Employee, core.class.Class, view.mixin.ObjectFactory, {
|
||||||
|
@ -514,7 +514,7 @@ export function createModel (builder: Builder): void {
|
|||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: documents.class.DocumentCategory,
|
ofClass: documents.class.DocumentCategory,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.mixin(documents.class.DocumentCategory, core.class.Class, view.mixin.ObjectPresenter, {
|
builder.mixin(documents.class.DocumentCategory, core.class.Class, view.mixin.ObjectPresenter, {
|
||||||
@ -768,7 +768,7 @@ export function defineNotifications (builder: Builder): void {
|
|||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: documents.class.DocumentComment,
|
ofClass: documents.class.DocumentComment,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.mixin(documents.class.ControlledDocument, core.class.Class, notification.mixin.ClassCollaborators, {
|
builder.mixin(documents.class.ControlledDocument, core.class.Class, notification.mixin.ClassCollaborators, {
|
||||||
|
@ -492,7 +492,7 @@ function defineDocument (builder: Builder): void {
|
|||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: document.class.Document,
|
ofClass: document.class.Document,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
// Search
|
// Search
|
||||||
|
@ -595,7 +595,7 @@ function defineFile (builder: Builder): void {
|
|||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: drive.class.File,
|
ofClass: drive.class.File,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
// Search
|
// Search
|
||||||
|
@ -85,17 +85,17 @@ export function createModel (builder: Builder): void {
|
|||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: inventory.class.Product,
|
ofClass: inventory.class.Product,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: inventory.class.Category,
|
ofClass: inventory.class.Category,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: inventory.class.Variant,
|
ofClass: inventory.class.Variant,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.mixin(inventory.class.Category, core.class.Class, view.mixin.ObjectPresenter, {
|
builder.mixin(inventory.class.Category, core.class.Class, view.mixin.ObjectPresenter, {
|
||||||
|
@ -51,12 +51,12 @@ export function createModel (builder: Builder): void {
|
|||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: lead.class.Lead,
|
ofClass: lead.class.Lead,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: lead.class.Funnel,
|
ofClass: lead.class.Funnel,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.mixin(lead.class.Funnel, core.class.Class, workbench.mixin.SpaceView, {
|
builder.mixin(lead.class.Funnel, core.class.Class, workbench.mixin.SpaceView, {
|
||||||
|
@ -28,8 +28,8 @@
|
|||||||
"typescript": "^5.3.3"
|
"typescript": "^5.3.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hcengineering/attachment": "^0.6.14",
|
|
||||||
"@hcengineering/activity": "^0.6.0",
|
"@hcengineering/activity": "^0.6.0",
|
||||||
|
"@hcengineering/attachment": "^0.6.14",
|
||||||
"@hcengineering/chunter": "^0.6.20",
|
"@hcengineering/chunter": "^0.6.20",
|
||||||
"@hcengineering/contact": "^0.6.24",
|
"@hcengineering/contact": "^0.6.24",
|
||||||
"@hcengineering/core": "^0.6.32",
|
"@hcengineering/core": "^0.6.32",
|
||||||
@ -46,6 +46,7 @@
|
|||||||
"@hcengineering/notification": "^0.6.23",
|
"@hcengineering/notification": "^0.6.23",
|
||||||
"@hcengineering/platform": "^0.6.11",
|
"@hcengineering/platform": "^0.6.11",
|
||||||
"@hcengineering/setting": "^0.6.17",
|
"@hcengineering/setting": "^0.6.17",
|
||||||
|
"@hcengineering/time": "^0.6.0",
|
||||||
"@hcengineering/ui": "^0.6.15",
|
"@hcengineering/ui": "^0.6.15",
|
||||||
"@hcengineering/view": "^0.6.13",
|
"@hcengineering/view": "^0.6.13",
|
||||||
"@hcengineering/workbench": "^0.6.16"
|
"@hcengineering/workbench": "^0.6.16"
|
||||||
|
@ -20,7 +20,10 @@ import {
|
|||||||
DOMAIN_TRANSIENT,
|
DOMAIN_TRANSIENT,
|
||||||
IndexKind,
|
IndexKind,
|
||||||
type Ref,
|
type Ref,
|
||||||
type CollaborativeDoc
|
type CollaborativeDoc,
|
||||||
|
type Doc,
|
||||||
|
type Timestamp,
|
||||||
|
type CollectionSize
|
||||||
} from '@hcengineering/core'
|
} from '@hcengineering/core'
|
||||||
import {
|
import {
|
||||||
type DevicesPreference,
|
type DevicesPreference,
|
||||||
@ -37,7 +40,8 @@ import {
|
|||||||
type RoomInfo,
|
type RoomInfo,
|
||||||
type RoomType,
|
type RoomType,
|
||||||
type RoomLanguage,
|
type RoomLanguage,
|
||||||
type MeetingMinutes
|
type MeetingMinutes,
|
||||||
|
type MeetingStatus
|
||||||
} from '@hcengineering/love'
|
} from '@hcengineering/love'
|
||||||
import {
|
import {
|
||||||
type Builder,
|
type Builder,
|
||||||
@ -52,7 +56,9 @@ import {
|
|||||||
TypeCollaborativeDoc,
|
TypeCollaborativeDoc,
|
||||||
TypeRef,
|
TypeRef,
|
||||||
TypeString,
|
TypeString,
|
||||||
UX
|
TypeTimestamp,
|
||||||
|
UX,
|
||||||
|
TypeAny
|
||||||
} from '@hcengineering/model'
|
} from '@hcengineering/model'
|
||||||
import calendar, { TEvent } from '@hcengineering/model-calendar'
|
import calendar, { TEvent } from '@hcengineering/model-calendar'
|
||||||
import core, { TAttachedDoc, TDoc } from '@hcengineering/model-core'
|
import core, { TAttachedDoc, TDoc } from '@hcengineering/model-core'
|
||||||
@ -66,6 +72,7 @@ import workbench, { WidgetType } from '@hcengineering/workbench'
|
|||||||
import activity from '@hcengineering/activity'
|
import activity from '@hcengineering/activity'
|
||||||
import chunter from '@hcengineering/chunter'
|
import chunter from '@hcengineering/chunter'
|
||||||
import attachment from '@hcengineering/attachment'
|
import attachment from '@hcengineering/attachment'
|
||||||
|
import time, { type ToDo, type Todoable } from '@hcengineering/time'
|
||||||
|
|
||||||
import love from './plugin'
|
import love from './plugin'
|
||||||
|
|
||||||
@ -107,6 +114,9 @@ export class TRoom extends TDoc implements Room {
|
|||||||
|
|
||||||
@Prop(PropCollection(love.class.MeetingMinutes), love.string.MeetingMinutes)
|
@Prop(PropCollection(love.class.MeetingMinutes), love.string.MeetingMinutes)
|
||||||
meetings?: number
|
meetings?: number
|
||||||
|
|
||||||
|
@Prop(PropCollection(chunter.class.ChatMessage), activity.string.Messages)
|
||||||
|
messages?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
@Model(love.class.Office, love.class.Room)
|
@Model(love.class.Office, love.class.Room)
|
||||||
@ -184,8 +194,13 @@ export class TMeeting extends TEvent implements Meeting {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Model(love.class.MeetingMinutes, core.class.Doc, DOMAIN_MEETING_MINUTES)
|
@Model(love.class.MeetingMinutes, core.class.Doc, DOMAIN_MEETING_MINUTES)
|
||||||
@UX(love.string.MeetingMinutes, love.icon.Cam)
|
@UX(love.string.MeetingMinutes, love.icon.Cam, undefined, 'createdOn', undefined, love.string.MeetingsMinutes)
|
||||||
export class TMeetingMinutes extends TAttachedDoc implements MeetingMinutes {
|
export class TMeetingMinutes extends TAttachedDoc implements MeetingMinutes, Todoable {
|
||||||
|
@Prop(TypeRef(core.class.Doc), love.string.Room, { editor: love.component.MeetingMinutesDocEditor })
|
||||||
|
@Index(IndexKind.Indexed)
|
||||||
|
@ReadOnly()
|
||||||
|
declare attachedTo: Ref<Doc>
|
||||||
|
|
||||||
@Hidden()
|
@Hidden()
|
||||||
sid!: string
|
sid!: string
|
||||||
|
|
||||||
@ -197,6 +212,12 @@ export class TMeetingMinutes extends TAttachedDoc implements MeetingMinutes {
|
|||||||
@Index(IndexKind.FullText)
|
@Index(IndexKind.FullText)
|
||||||
description!: CollaborativeDoc
|
description!: CollaborativeDoc
|
||||||
|
|
||||||
|
@Prop(TypeAny(love.component.MeetingMinutesStatusPresenter, love.string.Status), love.string.Status, {
|
||||||
|
editor: love.component.MeetingMinutesStatusPresenter
|
||||||
|
})
|
||||||
|
@ReadOnly()
|
||||||
|
status!: MeetingStatus
|
||||||
|
|
||||||
@Prop(Collection(attachment.class.Attachment), attachment.string.Attachments, { shortLabel: attachment.string.Files })
|
@Prop(Collection(attachment.class.Attachment), attachment.string.Attachments, { shortLabel: attachment.string.Files })
|
||||||
attachments?: number
|
attachments?: number
|
||||||
|
|
||||||
@ -205,6 +226,18 @@ export class TMeetingMinutes extends TAttachedDoc implements MeetingMinutes {
|
|||||||
|
|
||||||
@Prop(PropCollection(chunter.class.ChatMessage), activity.string.Messages)
|
@Prop(PropCollection(chunter.class.ChatMessage), activity.string.Messages)
|
||||||
messages?: number
|
messages?: number
|
||||||
|
|
||||||
|
@Prop(TypeTimestamp(), love.string.MeetingStart, { editor: view.component.TimestampPresenter })
|
||||||
|
@ReadOnly()
|
||||||
|
@Index(IndexKind.IndexedDsc)
|
||||||
|
declare createdOn: Timestamp
|
||||||
|
|
||||||
|
@Prop(TypeTimestamp(), love.string.MeetingEnd)
|
||||||
|
@ReadOnly()
|
||||||
|
meetingEnd?: Timestamp
|
||||||
|
|
||||||
|
@Prop(Collection(time.class.ToDo), getEmbeddedLabel('Action Items'))
|
||||||
|
todos?: CollectionSize<ToDo>
|
||||||
}
|
}
|
||||||
|
|
||||||
export default love
|
export default love
|
||||||
@ -418,17 +451,17 @@ export function createModel (builder: Builder): void {
|
|||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: love.class.Room,
|
ofClass: love.class.Room,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput, props: { collection: 'messages' } } }
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: love.class.Office,
|
ofClass: love.class.Office,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput, props: { collection: 'messages' } } }
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: love.class.MeetingMinutes,
|
ofClass: love.class.MeetingMinutes,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput, props: { collection: 'messages' } } }
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.mixin(love.class.MeetingMinutes, core.class.Class, activity.mixin.ActivityDoc, {})
|
builder.mixin(love.class.MeetingMinutes, core.class.Class, activity.mixin.ActivityDoc, {})
|
||||||
@ -439,6 +472,10 @@ export function createModel (builder: Builder): void {
|
|||||||
presenter: love.component.MeetingMinutesPresenter
|
presenter: love.component.MeetingMinutesPresenter
|
||||||
})
|
})
|
||||||
|
|
||||||
|
builder.mixin(love.class.Room, core.class.Class, view.mixin.ObjectPresenter, {
|
||||||
|
presenter: love.component.RoomPresenter
|
||||||
|
})
|
||||||
|
|
||||||
builder.mixin(love.class.MeetingMinutes, core.class.Class, view.mixin.CollectionEditor, {
|
builder.mixin(love.class.MeetingMinutes, core.class.Class, view.mixin.CollectionEditor, {
|
||||||
editor: love.component.MeetingMinutesSection
|
editor: love.component.MeetingMinutesSection
|
||||||
})
|
})
|
||||||
@ -467,10 +504,11 @@ export function createModel (builder: Builder): void {
|
|||||||
descriptor: view.viewlet.Table,
|
descriptor: view.viewlet.Table,
|
||||||
config: [
|
config: [
|
||||||
'',
|
'',
|
||||||
|
{ key: 'status', presenter: love.component.MeetingMinutesStatusPresenter, label: love.string.Status },
|
||||||
|
'createdOn',
|
||||||
|
'meetingEnd',
|
||||||
{ key: 'messages', displayProps: { key: 'messages', suffix: true } },
|
{ key: 'messages', displayProps: { key: 'messages', suffix: true } },
|
||||||
{ key: 'transcription', displayProps: { key: 'transcription', suffix: true } },
|
{ key: 'transcription', displayProps: { key: 'transcription', suffix: true } }
|
||||||
'modifiedOn',
|
|
||||||
'modifiedBy'
|
|
||||||
],
|
],
|
||||||
configOptions: {
|
configOptions: {
|
||||||
hiddenKeys: ['description'],
|
hiddenKeys: ['description'],
|
||||||
@ -481,6 +519,26 @@ export function createModel (builder: Builder): void {
|
|||||||
love.viewlet.TableMeetingMinutes
|
love.viewlet.TableMeetingMinutes
|
||||||
)
|
)
|
||||||
|
|
||||||
|
builder.createDoc(
|
||||||
|
view.class.Viewlet,
|
||||||
|
core.space.Model,
|
||||||
|
{
|
||||||
|
attachTo: love.class.MeetingMinutes,
|
||||||
|
descriptor: view.viewlet.Table,
|
||||||
|
config: [
|
||||||
|
'',
|
||||||
|
{ key: 'status', presenter: love.component.MeetingMinutesStatusPresenter, label: love.string.Status },
|
||||||
|
'createdOn',
|
||||||
|
'meetingEnd'
|
||||||
|
],
|
||||||
|
configOptions: {
|
||||||
|
sortable: true
|
||||||
|
},
|
||||||
|
variant: 'embedded'
|
||||||
|
},
|
||||||
|
love.viewlet.TableMeetingMinutesEmbedded
|
||||||
|
)
|
||||||
|
|
||||||
builder.createDoc(
|
builder.createDoc(
|
||||||
view.class.ViewletDescriptor,
|
view.class.ViewletDescriptor,
|
||||||
core.space.Model,
|
core.space.Model,
|
||||||
@ -574,4 +632,8 @@ export function createModel (builder: Builder): void {
|
|||||||
indexes: [],
|
indexes: [],
|
||||||
searchDisabled: true
|
searchDisabled: true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
builder.mixin(love.class.MeetingMinutes, core.class.Class, view.mixin.ObjectPanelFooter, {
|
||||||
|
editor: love.component.PanelControlBar
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,16 @@
|
|||||||
import contact from '@hcengineering/contact'
|
import contact from '@hcengineering/contact'
|
||||||
import { type Space, TxOperations, type Ref, makeCollaborativeDoc } from '@hcengineering/core'
|
import { type Space, TxOperations, type Ref, makeCollaborativeDoc } from '@hcengineering/core'
|
||||||
import drive from '@hcengineering/drive'
|
import drive from '@hcengineering/drive'
|
||||||
import { RoomAccess, RoomType, createDefaultRooms, isOffice, loveId, type Floor, type Room } from '@hcengineering/love'
|
import {
|
||||||
|
MeetingStatus,
|
||||||
|
RoomAccess,
|
||||||
|
RoomType,
|
||||||
|
createDefaultRooms,
|
||||||
|
isOffice,
|
||||||
|
loveId,
|
||||||
|
type Floor,
|
||||||
|
type Room
|
||||||
|
} from '@hcengineering/love'
|
||||||
import {
|
import {
|
||||||
createDefaultSpace,
|
createDefaultSpace,
|
||||||
migrateSpace,
|
migrateSpace,
|
||||||
@ -142,6 +151,16 @@ export const loveOperation: MigrateOperation = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: 'default-meeting-minutes-status',
|
||||||
|
func: async (client) => {
|
||||||
|
await client.update(
|
||||||
|
DOMAIN_MEETING_MINUTES,
|
||||||
|
{ status: { $exists: false } },
|
||||||
|
{ status: MeetingStatus.Finished }
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
|
@ -159,7 +159,7 @@ function defineProduct (builder: Builder): void {
|
|||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: products.class.Product,
|
ofClass: products.class.Product,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.mixin(products.class.Product, core.class.Class, view.mixin.ObjectEditor, {
|
builder.mixin(products.class.Product, core.class.Class, view.mixin.ObjectEditor, {
|
||||||
@ -299,7 +299,7 @@ function defineProductVersion (builder: Builder): void {
|
|||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: products.class.ProductVersion,
|
ofClass: products.class.ProductVersion,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.mixin(products.class.ProductVersion, core.class.Class, view.mixin.ObjectEditor, {
|
builder.mixin(products.class.ProductVersion, core.class.Class, view.mixin.ObjectEditor, {
|
||||||
|
@ -56,17 +56,17 @@ export function createModel (builder: Builder): void {
|
|||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: recruit.class.Vacancy,
|
ofClass: recruit.class.Vacancy,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: recruit.class.Applicant,
|
ofClass: recruit.class.Applicant,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: recruit.class.Review,
|
ofClass: recruit.class.Review,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.mixin(recruit.class.Vacancy, core.class.Class, workbench.mixin.SpaceView, {
|
builder.mixin(recruit.class.Vacancy, core.class.Class, workbench.mixin.SpaceView, {
|
||||||
|
@ -99,7 +99,7 @@ export function createModel (builder: Builder): void {
|
|||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: survey.class.Survey,
|
ofClass: survey.class.Survey,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.createDoc<Viewlet>(
|
builder.createDoc<Viewlet>(
|
||||||
@ -137,7 +137,7 @@ export function createModel (builder: Builder): void {
|
|||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: survey.class.Poll,
|
ofClass: survey.class.Poll,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.mixin(survey.class.Poll, core.class.Class, view.mixin.CollectionEditor, {
|
builder.mixin(survey.class.Poll, core.class.Class, view.mixin.CollectionEditor, {
|
||||||
|
@ -143,7 +143,7 @@ export function createModel (builder: Builder): void {
|
|||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: testManagement.class.TestProject,
|
ofClass: testManagement.class.TestProject,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
defineTestSuite(builder)
|
defineTestSuite(builder)
|
||||||
@ -218,7 +218,7 @@ function defineTestSuite (builder: Builder): void {
|
|||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: testManagement.class.TestSuite,
|
ofClass: testManagement.class.TestSuite,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.mixin(testManagement.class.TestSuite, core.class.Class, view.mixin.ObjectEditor, {
|
builder.mixin(testManagement.class.TestSuite, core.class.Class, view.mixin.ObjectEditor, {
|
||||||
@ -283,7 +283,7 @@ function defineTestCase (builder: Builder): void {
|
|||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: testManagement.class.TestCase,
|
ofClass: testManagement.class.TestCase,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.mixin(testManagement.class.TestCase, core.class.Class, view.mixin.ObjectEditor, {
|
builder.mixin(testManagement.class.TestCase, core.class.Class, view.mixin.ObjectEditor, {
|
||||||
@ -388,7 +388,7 @@ function defineTestRun (builder: Builder): void {
|
|||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: testManagement.class.TestRun,
|
ofClass: testManagement.class.TestRun,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.mixin(testManagement.class.TestRun, core.class.Class, view.mixin.ObjectEditor, {
|
builder.mixin(testManagement.class.TestRun, core.class.Class, view.mixin.ObjectEditor, {
|
||||||
|
@ -461,22 +461,22 @@ export function createModel (builder: Builder): void {
|
|||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: tracker.class.Issue,
|
ofClass: tracker.class.Issue,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: tracker.class.Milestone,
|
ofClass: tracker.class.Milestone,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: tracker.class.Component,
|
ofClass: tracker.class.Component,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: tracker.class.IssueTemplate,
|
ofClass: tracker.class.IssueTemplate,
|
||||||
components: { input: chunter.component.ChatMessageInput }
|
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||||
})
|
})
|
||||||
|
|
||||||
defineViewlets(builder)
|
defineViewlets(builder)
|
||||||
|
@ -67,6 +67,7 @@ import {
|
|||||||
type ListItemPresenter,
|
type ListItemPresenter,
|
||||||
type ObjectEditor,
|
type ObjectEditor,
|
||||||
type ObjectEditorFooter,
|
type ObjectEditorFooter,
|
||||||
|
type ObjectPanelFooter,
|
||||||
type ObjectEditorHeader,
|
type ObjectEditorHeader,
|
||||||
type ObjectFactory,
|
type ObjectFactory,
|
||||||
type ObjectPanel,
|
type ObjectPanel,
|
||||||
@ -216,6 +217,11 @@ export class TObjectEditorFooter extends TClass implements ObjectEditorFooter {
|
|||||||
editor!: AnyComponent
|
editor!: AnyComponent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Mixin(view.mixin.ObjectPanelFooter, core.class.Class)
|
||||||
|
export class TObjectPanelFooter extends TClass implements ObjectPanelFooter {
|
||||||
|
editor!: AnyComponent
|
||||||
|
}
|
||||||
|
|
||||||
@Mixin(view.mixin.SpaceHeader, core.class.Class)
|
@Mixin(view.mixin.SpaceHeader, core.class.Class)
|
||||||
export class TSpaceHeader extends TClass implements SpaceHeader {
|
export class TSpaceHeader extends TClass implements SpaceHeader {
|
||||||
header!: AnyComponent
|
header!: AnyComponent
|
||||||
@ -445,6 +451,7 @@ export function createModel (builder: Builder): void {
|
|||||||
TObjectTitle,
|
TObjectTitle,
|
||||||
TObjectEditorHeader,
|
TObjectEditorHeader,
|
||||||
TObjectEditorFooter,
|
TObjectEditorFooter,
|
||||||
|
TObjectPanelFooter,
|
||||||
TSpaceHeader,
|
TSpaceHeader,
|
||||||
TSpaceName,
|
TSpaceName,
|
||||||
TSpacePresenter,
|
TSpacePresenter,
|
||||||
|
@ -158,6 +158,11 @@
|
|||||||
<svelte:fragment slot="pre-utils">
|
<svelte:fragment slot="pre-utils">
|
||||||
<slot name="pre-utils" />
|
<slot name="pre-utils" />
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
|
|
||||||
|
<svelte:fragment slot="panel-footer">
|
||||||
|
<slot name="panel-footer" />
|
||||||
|
</svelte:fragment>
|
||||||
|
|
||||||
<svelte:fragment slot="utils">
|
<svelte:fragment slot="utils">
|
||||||
{#if isUtils && $$slots.utils}
|
{#if isUtils && $$slots.utils}
|
||||||
<slot name="utils" />
|
<slot name="utils" />
|
||||||
|
@ -626,7 +626,7 @@ export async function getAttributeEditor (
|
|||||||
|
|
||||||
function filterKeys (hierarchy: Hierarchy, keys: KeyedAttribute[], ignoreKeys: string[]): KeyedAttribute[] {
|
function filterKeys (hierarchy: Hierarchy, keys: KeyedAttribute[], ignoreKeys: string[]): KeyedAttribute[] {
|
||||||
const docKeys: Set<string> = new Set<string>(hierarchy.getAllAttributes(core.class.AttachedDoc).keys())
|
const docKeys: Set<string> = new Set<string>(hierarchy.getAllAttributes(core.class.AttachedDoc).keys())
|
||||||
keys = keys.filter((k) => !docKeys.has(k.key))
|
keys = keys.filter((k) => !docKeys.has(k.key) || k.attr.editor !== undefined)
|
||||||
keys = keys.filter((k) => !ignoreKeys.includes(k.key))
|
keys = keys.filter((k) => !ignoreKeys.includes(k.key))
|
||||||
return keys
|
return keys
|
||||||
}
|
}
|
||||||
|
@ -309,6 +309,11 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
{#if $$slots['panel-footer']}
|
||||||
|
<div class="popupPanel-footer">
|
||||||
|
<slot name="panel-footer" />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
<div class="popupPanel-pageHeader only-print" id="page-header">
|
<div class="popupPanel-pageHeader only-print" id="page-header">
|
||||||
<slot name="page-header" />
|
<slot name="page-header" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -372,7 +372,8 @@ export function fitPopupElement (
|
|||||||
newProps.right = '1px'
|
newProps.right = '1px'
|
||||||
show = true
|
show = true
|
||||||
} else if (element === 'full-centered') {
|
} else if (element === 'full-centered') {
|
||||||
newProps.top = '20px'
|
const rect = contentPanel !== undefined ? contentPanel.getBoundingClientRect() : { top: 0 }
|
||||||
|
newProps.top = `${Math.max(20, rect.top + 1)}px`
|
||||||
newProps.bottom = '20px'
|
newProps.bottom = '20px'
|
||||||
newProps.left = '20px'
|
newProps.left = '20px'
|
||||||
newProps.right = '20px'
|
newProps.right = '20px'
|
||||||
|
@ -24,5 +24,11 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if extension}
|
{#if extension}
|
||||||
<Component is={extension.components[kind]} {props} on:close on:open on:submit />
|
<Component
|
||||||
|
is={extension.components[kind].component}
|
||||||
|
props={{ ...extension.components[kind].props, ...props }}
|
||||||
|
on:close
|
||||||
|
on:open
|
||||||
|
on:submit
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
$: attrViewletConfig = viewlet?.config?.[attributeModel.key]
|
$: attrViewletConfig = viewlet?.config?.[attributeModel.key]
|
||||||
$: attributeIcon = attrViewletConfig?.icon ?? attributeModel.icon ?? IconEdit
|
$: attributeIcon = attrViewletConfig?.icon ?? attributeModel.icon ?? IconEdit
|
||||||
$: isUnset = values.length > 0 && !values.some((value) => value !== null && value !== '')
|
$: isUnset = values.length > 0 && !values.some((value) => value != null && value !== '')
|
||||||
|
|
||||||
$: isTextType = getIsTextType(attributeModel)
|
$: isTextType = getIsTextType(attributeModel)
|
||||||
|
|
||||||
@ -42,7 +42,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if isUnset}
|
{#if isUnset}
|
||||||
<div class="row overflow-label">
|
<div class="unset row overflow-label">
|
||||||
<span class="mr-1"><Icon icon={attributeIcon} size="small" /></span>
|
<span class="mr-1"><Icon icon={attributeIcon} size="small" /></span>
|
||||||
<Label label={activity.string.Unset} />
|
<Label label={activity.string.Unset} />
|
||||||
<span class="lower"><Label label={attributeModel.label} /></span>
|
<span class="lower"><Label label={attributeModel.label} /></span>
|
||||||
@ -89,6 +89,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.25rem;
|
gap: 0.25rem;
|
||||||
|
color: var(--global-primary-TextColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
.showMore {
|
.showMore {
|
||||||
|
@ -210,7 +210,7 @@ export type ActivityExtensionKind = 'input'
|
|||||||
*/
|
*/
|
||||||
export interface ActivityExtension extends Doc {
|
export interface ActivityExtension extends Doc {
|
||||||
ofClass: Ref<Class<Doc>>
|
ofClass: Ref<Class<Doc>>
|
||||||
components: Record<ActivityExtensionKind, AnyComponent>
|
components: Record<ActivityExtensionKind, { component: AnyComponent, props?: Record<string, any> }>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -72,9 +72,6 @@
|
|||||||
|
|
||||||
async function updateDataProvider (attachedTo: Ref<Doc>, selectedMessageId?: Ref<ActivityMessage>): Promise<void> {
|
async function updateDataProvider (attachedTo: Ref<Doc>, selectedMessageId?: Ref<ActivityMessage>): Promise<void> {
|
||||||
if (dataProvider === undefined) {
|
if (dataProvider === undefined) {
|
||||||
// For now loading all messages for documents with activity. Need to correct handle aggregation with pagination.
|
|
||||||
// Perhaps we should load all activity messages once, and keep loading in chunks only for ChatMessages then merge them correctly with activity messages
|
|
||||||
const loadAll = isDocChannel
|
|
||||||
const ctx =
|
const ctx =
|
||||||
context ??
|
context ??
|
||||||
(await client.findOne(notification.class.DocNotifyContext, {
|
(await client.findOne(notification.class.DocNotifyContext, {
|
||||||
@ -90,7 +87,7 @@
|
|||||||
attachedTo,
|
attachedTo,
|
||||||
activity.class.ActivityMessage,
|
activity.class.ActivityMessage,
|
||||||
selectedMessageId,
|
selectedMessageId,
|
||||||
loadAll,
|
false,
|
||||||
hasRefs,
|
hasRefs,
|
||||||
collection
|
collection
|
||||||
)
|
)
|
||||||
@ -112,7 +109,7 @@
|
|||||||
provider={dataProvider}
|
provider={dataProvider}
|
||||||
{freeze}
|
{freeze}
|
||||||
{autofocus}
|
{autofocus}
|
||||||
loadMoreAllowed={!isDocChannel}
|
loadMoreAllowed
|
||||||
{withInput}
|
{withInput}
|
||||||
{readonly}
|
{readonly}
|
||||||
{onReply}
|
{onReply}
|
||||||
|
@ -68,9 +68,15 @@
|
|||||||
"Transcription": "Transcription",
|
"Transcription": "Transcription",
|
||||||
"StartWithTranscription": "Start with transcription",
|
"StartWithTranscription": "Start with transcription",
|
||||||
"MeetingMinutes": "Meeting minutes",
|
"MeetingMinutes": "Meeting minutes",
|
||||||
|
"MeetingsMinutes": "Meetings minutes",
|
||||||
"StartMeeting": "Start meeting",
|
"StartMeeting": "Start meeting",
|
||||||
"Video": "Video",
|
"Video": "Video",
|
||||||
"NoMeetingMinutes": "No meeting minutes",
|
"NoMeetingMinutes": "No meeting minutes",
|
||||||
"JoinMeeting": "Join meeting"
|
"JoinMeeting": "Join meeting",
|
||||||
|
"MeetingStart": "Meeting start",
|
||||||
|
"MeetingEnd": "Meeting end",
|
||||||
|
"Status": "Status",
|
||||||
|
"Active": "Active",
|
||||||
|
"Finished": "Finished"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,9 +68,15 @@
|
|||||||
"Transcription": "Transcripción",
|
"Transcription": "Transcripción",
|
||||||
"StartWithTranscription": "Iniciar con transcripción",
|
"StartWithTranscription": "Iniciar con transcripción",
|
||||||
"MeetingMinutes": "Minutos de la reunión",
|
"MeetingMinutes": "Minutos de la reunión",
|
||||||
|
"MeetingsMinutes": "Minutos de las reuniones",
|
||||||
"StartMeeting": "Iniciar reunión",
|
"StartMeeting": "Iniciar reunión",
|
||||||
"Video": "Video",
|
"Video": "Video",
|
||||||
"NoMeetingMinutes": "Sin minutos de reunión",
|
"NoMeetingMinutes": "Sin minutos de reunión",
|
||||||
"JoinMeeting": "Unirse a la reunión"
|
"JoinMeeting": "Unirse a la reunión",
|
||||||
|
"MeetingStart": "Inicio de la reunión",
|
||||||
|
"MeetingEnd": "Fin de la reunión",
|
||||||
|
"Status": "Estado",
|
||||||
|
"Active": "Activo",
|
||||||
|
"Finished": "Terminado"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,9 +68,15 @@
|
|||||||
"Transcription": "Transcription",
|
"Transcription": "Transcription",
|
||||||
"StartWithTranscription": "Démarrer avec la transcription",
|
"StartWithTranscription": "Démarrer avec la transcription",
|
||||||
"MeetingMinutes": "Minutes de la réunion",
|
"MeetingMinutes": "Minutes de la réunion",
|
||||||
|
"MeetingsMinutes": "Minutes des réunions",
|
||||||
"StartMeeting": "Démarrer la réunion",
|
"StartMeeting": "Démarrer la réunion",
|
||||||
"Video": "Vidéo",
|
"Video": "Vidéo",
|
||||||
"NoMeetingMinutes": "Pas de minutes de réunion",
|
"NoMeetingMinutes": "Pas de minutes de réunion",
|
||||||
"JoinMeeting": "Rejoindre la réunion"
|
"JoinMeeting": "Rejoindre la réunion",
|
||||||
|
"MeetingStart": "Début de la réunion",
|
||||||
|
"MeetingEnd": "Fin de la réunion",
|
||||||
|
"Status": "Statut",
|
||||||
|
"Active": "Actif",
|
||||||
|
"Finished": "Terminé"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -68,9 +68,15 @@
|
|||||||
"Transcription": "Trascrizione",
|
"Transcription": "Trascrizione",
|
||||||
"StartWithTranscription": "Inizia con la trascrizione",
|
"StartWithTranscription": "Inizia con la trascrizione",
|
||||||
"MeetingMinutes": "Verbale della riunione",
|
"MeetingMinutes": "Verbale della riunione",
|
||||||
|
"MeetingsMinutes": "Verbali delle riunioni",
|
||||||
"StartMeeting": "Inizia riunione",
|
"StartMeeting": "Inizia riunione",
|
||||||
"Video": "Video",
|
"Video": "Video",
|
||||||
"NoMeetingMinutes": "Nessun verbale della riunione",
|
"NoMeetingMinutes": "Nessun verbale della riunione",
|
||||||
"JoinMeeting": "Unisciti alla riunione"
|
"JoinMeeting": "Unisciti alla riunione",
|
||||||
|
"MeetingStart": "Inizio riunione",
|
||||||
|
"MeetingEnd": "Fine riunione",
|
||||||
|
"Status": "Stato",
|
||||||
|
"Active": "Attivo",
|
||||||
|
"Finished": "Finito"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,9 +68,15 @@
|
|||||||
"Transcription": "Transcrição",
|
"Transcription": "Transcrição",
|
||||||
"StartWithTranscription": "Começar com transcrição",
|
"StartWithTranscription": "Começar com transcrição",
|
||||||
"MeetingMinutes": "Minutos da reunião",
|
"MeetingMinutes": "Minutos da reunião",
|
||||||
|
"MeetingsMinutes": "Minutos das reuniões",
|
||||||
"StartMeeting": "Iniciar reunião",
|
"StartMeeting": "Iniciar reunião",
|
||||||
"Video": "Vídeo",
|
"Video": "Vídeo",
|
||||||
"NoMeetingMinutes": "Sem minutos de reunião",
|
"NoMeetingMinutes": "Sem minutos de reunião",
|
||||||
"JoinMeeting": "Participar na reunião"
|
"JoinMeeting": "Participar na reunião",
|
||||||
|
"MeetingStart": "Início da reunião",
|
||||||
|
"MeetingEnd": "Fim da reunião",
|
||||||
|
"Status": "Estado",
|
||||||
|
"Active": "Ativo",
|
||||||
|
"Finished": "Finalizado"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,10 +67,16 @@
|
|||||||
"Meeting": "Встреча",
|
"Meeting": "Встреча",
|
||||||
"Transcription": "Транскрипция",
|
"Transcription": "Транскрипция",
|
||||||
"StartWithTranscription": "Начинать с транскрипцией",
|
"StartWithTranscription": "Начинать с транскрипцией",
|
||||||
"MeetingMinutes": "Результаты встреч",
|
"MeetingMinutes": "Протокол встречи",
|
||||||
|
"MeetingsMinutes": "Протоколы встреч",
|
||||||
"StartMeeting": "Начать встречу",
|
"StartMeeting": "Начать встречу",
|
||||||
"Video": "Видео",
|
"Video": "Видео",
|
||||||
"NoMeetingMinutes": "Нет результатов встреч",
|
"NoMeetingMinutes": "Нет результатов встреч",
|
||||||
"JoinMeeting": "Присоединиться к встрече"
|
"JoinMeeting": "Присоединиться к встрече",
|
||||||
|
"MeetingStart": "Начало встречи",
|
||||||
|
"MeetingEnd": "Конец встречи",
|
||||||
|
"Status": "Статус",
|
||||||
|
"Active": "Активно",
|
||||||
|
"Finished": "Завершено"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,9 +68,15 @@
|
|||||||
"Transcription": "转录",
|
"Transcription": "转录",
|
||||||
"StartWithTranscription": "开始转录",
|
"StartWithTranscription": "开始转录",
|
||||||
"MeetingMinutes": "会议记录",
|
"MeetingMinutes": "会议记录",
|
||||||
|
"MeetingsMinutes": "会议记录",
|
||||||
"StartMeeting": "开始会议",
|
"StartMeeting": "开始会议",
|
||||||
"Video": "视频",
|
"Video": "视频",
|
||||||
"NoMeetingMinutes": "无会议记录",
|
"NoMeetingMinutes": "无会议记录",
|
||||||
"JoinMeeting": "加入会议"
|
"JoinMeeting": "加入会议",
|
||||||
|
"MeetingStart": "会议开始",
|
||||||
|
"MeetingEnd": "会议结束",
|
||||||
|
"Status": "状态",
|
||||||
|
"Active": "活动",
|
||||||
|
"Finished": "已完成"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,90 +0,0 @@
|
|||||||
<!--
|
|
||||||
// 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.
|
|
||||||
-->
|
|
||||||
<script lang="ts">
|
|
||||||
import { personByIdStore } from '@hcengineering/contact-resources'
|
|
||||||
import { Room as TypeRoom } from '@hcengineering/love'
|
|
||||||
import { getMetadata } from '@hcengineering/platform'
|
|
||||||
import { Label, Loading, deviceOptionsStore as deviceInfo } from '@hcengineering/ui'
|
|
||||||
import { onDestroy, onMount } from 'svelte'
|
|
||||||
import presentation, { getClient } from '@hcengineering/presentation'
|
|
||||||
import { EditDoc } from '@hcengineering/view-resources'
|
|
||||||
import { subscribeDoc } from '@hcengineering/notification-resources'
|
|
||||||
|
|
||||||
import love from '../plugin'
|
|
||||||
import { storePromise, currentRoom, infos, invites, myInfo, myRequests, meetingMinutesStore } from '../stores'
|
|
||||||
import { awaitConnect, isConnected, isCurrentInstanceConnected, isFullScreen, tryConnect } from '../utils'
|
|
||||||
import ControlBar from './ControlBar.svelte'
|
|
||||||
|
|
||||||
export let room: TypeRoom
|
|
||||||
|
|
||||||
let loading: boolean = false
|
|
||||||
let configured: boolean = false
|
|
||||||
|
|
||||||
onMount(async () => {
|
|
||||||
loading = true
|
|
||||||
|
|
||||||
const wsURL = getMetadata(love.metadata.WebSocketURL)
|
|
||||||
|
|
||||||
if (wsURL === undefined) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
configured = true
|
|
||||||
|
|
||||||
await $storePromise
|
|
||||||
|
|
||||||
if (
|
|
||||||
!$isConnected &&
|
|
||||||
!$isCurrentInstanceConnected &&
|
|
||||||
$myInfo?.sessionId === getMetadata(presentation.metadata.SessionId)
|
|
||||||
) {
|
|
||||||
const info = $infos.filter((p) => p.room === room._id)
|
|
||||||
await tryConnect($personByIdStore, $myInfo, room, info, $myRequests, $invites)
|
|
||||||
}
|
|
||||||
|
|
||||||
await awaitConnect()
|
|
||||||
loading = false
|
|
||||||
})
|
|
||||||
|
|
||||||
let replacedPanel: HTMLElement
|
|
||||||
$: $deviceInfo.replacedPanel = replacedPanel
|
|
||||||
onDestroy(() => ($deviceInfo.replacedPanel = undefined))
|
|
||||||
|
|
||||||
$: if ($meetingMinutesStore) {
|
|
||||||
void subscribeDoc(getClient(), $meetingMinutesStore._class, $meetingMinutesStore._id, 'add', $meetingMinutesStore)
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="antiPanel-component filledNav" bind:this={replacedPanel}>
|
|
||||||
<div class="hulyComponent">
|
|
||||||
{#if $isConnected && !$isCurrentInstanceConnected}
|
|
||||||
<div class="flex-center justify-center error h-full w-full clear-mins">
|
|
||||||
<Label label={love.string.AnotherWindowError} />
|
|
||||||
</div>
|
|
||||||
{:else if !configured}
|
|
||||||
<div class="flex-center justify-center error h-full w-full clear-mins">
|
|
||||||
<Label label={love.string.ServiceNotConfigured} />
|
|
||||||
</div>
|
|
||||||
{:else if loading || !$currentRoom || !$meetingMinutesStore}
|
|
||||||
<Loading />
|
|
||||||
{:else}
|
|
||||||
<EditDoc _id={$meetingMinutesStore._id} _class={$meetingMinutesStore._class} embedded selectedAside={false} />
|
|
||||||
{/if}
|
|
||||||
{#if $currentRoom}
|
|
||||||
<div class="flex-grow flex-shrink" />
|
|
||||||
<ControlBar room={$currentRoom} fullScreen={$isFullScreen} />
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@ -29,7 +29,8 @@
|
|||||||
type CompAndProps,
|
type CompAndProps,
|
||||||
IconMoreV,
|
IconMoreV,
|
||||||
ButtonMenu,
|
ButtonMenu,
|
||||||
DropdownIntlItem
|
DropdownIntlItem,
|
||||||
|
IconMaximize
|
||||||
} from '@hcengineering/ui'
|
} from '@hcengineering/ui'
|
||||||
import view, { Action } from '@hcengineering/view'
|
import view, { Action } from '@hcengineering/view'
|
||||||
import { getActions } from '@hcengineering/view-resources'
|
import { getActions } from '@hcengineering/view-resources'
|
||||||
@ -60,8 +61,10 @@
|
|||||||
import RoomAccessPopup from './RoomAccessPopup.svelte'
|
import RoomAccessPopup from './RoomAccessPopup.svelte'
|
||||||
import RoomLanguageSelector from './RoomLanguageSelector.svelte'
|
import RoomLanguageSelector from './RoomLanguageSelector.svelte'
|
||||||
import ControlBarContainer from './ControlBarContainer.svelte'
|
import ControlBarContainer from './ControlBarContainer.svelte'
|
||||||
|
import RoomModal from './RoomModal.svelte'
|
||||||
|
|
||||||
export let room: Room
|
export let room: Room
|
||||||
|
export let canMaximize: boolean = true
|
||||||
export let fullScreen: boolean = false
|
export let fullScreen: boolean = false
|
||||||
export let onFullScreen: (() => void) | undefined = undefined
|
export let onFullScreen: (() => void) | undefined = undefined
|
||||||
|
|
||||||
@ -159,6 +162,10 @@
|
|||||||
await fn(room)
|
await fn(room)
|
||||||
}
|
}
|
||||||
$: withVideo = $screenSharing || room.type === RoomType.Video
|
$: withVideo = $screenSharing || room.type === RoomType.Video
|
||||||
|
|
||||||
|
function maximize (): void {
|
||||||
|
showPopup(RoomModal, { room }, 'full-centered')
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ControlBarContainer bind:noLabel>
|
<ControlBarContainer bind:noLabel>
|
||||||
@ -253,6 +260,20 @@
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
{#if ($screenSharing || room.type === RoomType.Video) && $isConnected && canMaximize}
|
||||||
|
<ModernButton
|
||||||
|
icon={IconMaximize}
|
||||||
|
tooltip={{
|
||||||
|
label: love.string.FullscreenMode,
|
||||||
|
direction: 'top'
|
||||||
|
}}
|
||||||
|
kind={'secondary'}
|
||||||
|
iconSize="medium"
|
||||||
|
size={'large'}
|
||||||
|
on:click={maximize}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
{#if $isConnected && moreItems.length > 0}
|
{#if $isConnected && moreItems.length > 0}
|
||||||
<ButtonMenu
|
<ButtonMenu
|
||||||
items={moreItems}
|
items={moreItems}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
import { getClient } from '@hcengineering/presentation'
|
import { getClient } from '@hcengineering/presentation'
|
||||||
import { EditBox } from '@hcengineering/ui'
|
import { EditBox } from '@hcengineering/ui'
|
||||||
import { MeetingMinutes } from '@hcengineering/love'
|
import { MeetingMinutes } from '@hcengineering/love'
|
||||||
|
import { createEventDispatcher, onMount } from 'svelte'
|
||||||
|
|
||||||
import love from '../plugin'
|
import love from '../plugin'
|
||||||
|
|
||||||
@ -23,10 +24,15 @@
|
|||||||
export let readonly: boolean = false
|
export let readonly: boolean = false
|
||||||
|
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
async function changeTitle (): Promise<void> {
|
async function changeTitle (): Promise<void> {
|
||||||
await client.diffUpdate(object, { title: object.title })
|
await client.update(object, { title: object.title })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
dispatch('open', { ignoreKeys: ['title'] })
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex-row-stretch">
|
<div class="flex-row-stretch">
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { getClient } from '@hcengineering/presentation'
|
import { getClient } from '@hcengineering/presentation'
|
||||||
import { EditBox, ModernButton, closePanel } from '@hcengineering/ui'
|
import { EditBox, ModernButton } from '@hcengineering/ui'
|
||||||
import { Room, isOffice } from '@hcengineering/love'
|
import { Room, isOffice } from '@hcengineering/love'
|
||||||
import { createEventDispatcher, onMount } from 'svelte'
|
import { createEventDispatcher, onMount } from 'svelte'
|
||||||
import { personByIdStore } from '@hcengineering/contact-resources'
|
import { personByIdStore } from '@hcengineering/contact-resources'
|
||||||
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
import love from '../plugin'
|
import love from '../plugin'
|
||||||
import { getRoomName, tryConnect } from '../utils'
|
import { getRoomName, tryConnect } from '../utils'
|
||||||
import { infos, invites, myInfo, myRequests, selectedRoomPlace } from '../stores'
|
import { infos, invites, myInfo, myRequests, selectedRoomPlace, myOffice, currentRoom } from '../stores'
|
||||||
|
|
||||||
export let object: Room
|
export let object: Room
|
||||||
export let readonly: boolean = false
|
export let readonly: boolean = false
|
||||||
@ -59,8 +59,6 @@
|
|||||||
)
|
)
|
||||||
connecting = false
|
connecting = false
|
||||||
selectedRoomPlace.set(undefined)
|
selectedRoomPlace.set(undefined)
|
||||||
closePanel()
|
|
||||||
dispatch('close')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let connectLabel: IntlString = love.string.StartMeeting
|
let connectLabel: IntlString = love.string.StartMeeting
|
||||||
@ -83,7 +81,9 @@
|
|||||||
focusIndex={1}
|
focusIndex={1}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<ModernButton label={connectLabel} size="large" kind={'primary'} on:click={connect} loading={connecting} />
|
{#if object._id !== $myOffice?._id && ($currentRoom?._id !== object._id || connecting)}
|
||||||
|
<ModernButton label={connectLabel} size="large" kind={'primary'} on:click={connect} loading={connecting} />
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -14,12 +14,15 @@
|
|||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { deviceOptionsStore as deviceInfo } from '@hcengineering/ui'
|
import { deviceOptionsStore as deviceInfo } from '@hcengineering/ui'
|
||||||
import { onDestroy } from 'svelte'
|
import { onDestroy, onMount } from 'svelte'
|
||||||
|
import presentation from '@hcengineering/presentation'
|
||||||
|
import { personByIdStore } from '@hcengineering/contact-resources'
|
||||||
|
|
||||||
import Hall from './Hall.svelte'
|
import Hall from './Hall.svelte'
|
||||||
import { currentRoom } from '../stores'
|
import { getMetadata } from '@hcengineering/platform'
|
||||||
import { isConnected } from '../utils'
|
import love from '../plugin'
|
||||||
import ActiveMeeting from './ActiveMeeting.svelte'
|
import { tryConnect, isConnected, isCurrentInstanceConnected } from '../utils'
|
||||||
|
import { infos, invites, myInfo, myRequests, storePromise, currentRoom } from '../stores'
|
||||||
|
|
||||||
const localNav: boolean = $deviceInfo.navigator.visible
|
const localNav: boolean = $deviceInfo.navigator.visible
|
||||||
const savedNav = localStorage.getItem('love-visibleNav')
|
const savedNav = localStorage.getItem('love-visibleNav')
|
||||||
@ -29,12 +32,30 @@
|
|||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
$deviceInfo.navigator.visible = localNav
|
$deviceInfo.navigator.visible = localNav
|
||||||
})
|
})
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
const wsURL = getMetadata(love.metadata.WebSocketURL)
|
||||||
|
|
||||||
|
if (wsURL === undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await $storePromise
|
||||||
|
const room = $currentRoom
|
||||||
|
|
||||||
|
if (room === undefined) return
|
||||||
|
|
||||||
|
if (
|
||||||
|
!$isConnected &&
|
||||||
|
!$isCurrentInstanceConnected &&
|
||||||
|
$myInfo?.sessionId === getMetadata(presentation.metadata.SessionId)
|
||||||
|
) {
|
||||||
|
const info = $infos.filter((p) => p.room === room._id)
|
||||||
|
await tryConnect($personByIdStore, $myInfo, room, info, $myRequests, $invites)
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="hulyPanels-container">
|
<div class="hulyPanels-container">
|
||||||
{#if $currentRoom && $isConnected}
|
<Hall />
|
||||||
<ActiveMeeting room={$currentRoom} />
|
|
||||||
{:else}
|
|
||||||
<Hall />
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -0,0 +1,54 @@
|
|||||||
|
<!--
|
||||||
|
// 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.
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
import { MeetingMinutes } from '@hcengineering/love'
|
||||||
|
import { ObjectPresenter, openDoc } from '@hcengineering/view-resources'
|
||||||
|
import view from '@hcengineering/view'
|
||||||
|
import { ActionIcon } from '@hcengineering/ui'
|
||||||
|
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||||
|
import type { Doc } from '@hcengineering/core'
|
||||||
|
|
||||||
|
export let object: MeetingMinutes
|
||||||
|
|
||||||
|
const client = getClient()
|
||||||
|
const docQuery = createQuery()
|
||||||
|
|
||||||
|
let doc: Doc | undefined
|
||||||
|
|
||||||
|
$: docQuery.query(object.attachedToClass, { _id: object.attachedTo }, (r) => {
|
||||||
|
doc = r.shift()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if doc}
|
||||||
|
<span class="label flex-row-center flex-gap-4 ml-3 no-word-wrap">
|
||||||
|
<ObjectPresenter
|
||||||
|
objectId={doc._id}
|
||||||
|
_class={doc._class}
|
||||||
|
value={doc}
|
||||||
|
shouldShowAvatar={false}
|
||||||
|
disabled
|
||||||
|
props={{ type: 'text' }}
|
||||||
|
/>
|
||||||
|
<ActionIcon
|
||||||
|
icon={view.icon.Open}
|
||||||
|
size={'small'}
|
||||||
|
action={async () => {
|
||||||
|
if (doc === undefined) return
|
||||||
|
await openDoc(client.getHierarchy(), doc)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
{/if}
|
@ -15,24 +15,43 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Class, Doc, Ref, Space } from '@hcengineering/core'
|
import type { Class, Doc, Ref, Space } from '@hcengineering/core'
|
||||||
import { Label, Section } from '@hcengineering/ui'
|
import { Label, Section } from '@hcengineering/ui'
|
||||||
import { Table } from '@hcengineering/view-resources'
|
import { Table, ViewletsSettingButton } from '@hcengineering/view-resources'
|
||||||
import love from '@hcengineering/love'
|
import { Viewlet, ViewletPreference } from '@hcengineering/view'
|
||||||
|
|
||||||
|
import love from '../plugin'
|
||||||
|
|
||||||
export let objectId: Ref<Doc>
|
export let objectId: Ref<Doc>
|
||||||
export let space: Ref<Space>
|
export let space: Ref<Space>
|
||||||
export let _class: Ref<Class<Doc>>
|
export let _class: Ref<Class<Doc>>
|
||||||
export let readonly: boolean = false
|
export let readonly: boolean = false
|
||||||
export let meetings: number
|
export let meetings: number
|
||||||
|
|
||||||
|
let viewlet: Viewlet | undefined
|
||||||
|
let preference: ViewletPreference | undefined
|
||||||
|
let loading = true
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Section label={love.string.MeetingMinutes} icon={love.icon.Cam}>
|
<Section label={love.string.MeetingMinutes} icon={love.icon.Cam}>
|
||||||
|
<svelte:fragment slot="header">
|
||||||
|
<div class="flex-row-center gap-2 reverse">
|
||||||
|
<ViewletsSettingButton
|
||||||
|
viewletQuery={{ _id: love.viewlet.TableMeetingMinutesEmbedded }}
|
||||||
|
kind={'tertiary'}
|
||||||
|
bind:viewlet
|
||||||
|
bind:loading
|
||||||
|
bind:preference
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</svelte:fragment>
|
||||||
|
|
||||||
<svelte:fragment slot="content">
|
<svelte:fragment slot="content">
|
||||||
{#if meetings > 0}
|
{#if meetings > 0 && viewlet}
|
||||||
<Table
|
<Table
|
||||||
_class={love.class.MeetingMinutes}
|
_class={love.class.MeetingMinutes}
|
||||||
config={['', 'transcription', 'messages']}
|
config={preference?.config ?? viewlet.config}
|
||||||
query={{ attachedTo: objectId }}
|
query={{ attachedTo: objectId }}
|
||||||
loadingProps={{ length: meetings }}
|
loadingProps={{ length: meetings }}
|
||||||
|
prefferedSorting="createdOn"
|
||||||
{readonly}
|
{readonly}
|
||||||
/>
|
/>
|
||||||
{:else}
|
{:else}
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
<!--
|
||||||
|
// 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.
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
import { MeetingMinutes, MeetingStatus } from '@hcengineering/love'
|
||||||
|
import { StateType, StateTag } from '@hcengineering/ui'
|
||||||
|
|
||||||
|
import love from '../plugin'
|
||||||
|
|
||||||
|
export let object: MeetingMinutes | undefined
|
||||||
|
export let value: MeetingStatus | undefined
|
||||||
|
export let attributeKey: string | undefined
|
||||||
|
|
||||||
|
const displayData = {
|
||||||
|
[MeetingStatus.Active]: {
|
||||||
|
label: love.string.Active,
|
||||||
|
type: StateType.Positive
|
||||||
|
},
|
||||||
|
[MeetingStatus.Finished]: {
|
||||||
|
label: love.string.Finished,
|
||||||
|
type: StateType.Regular
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let status: MeetingStatus | undefined
|
||||||
|
|
||||||
|
$: status = value ?? object?.status
|
||||||
|
$: data = status !== undefined ? displayData[status] : undefined
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if data}
|
||||||
|
<span class="flex-row-center" class:ml-3={attributeKey !== undefined}>
|
||||||
|
<StateTag type={data.type} label={data.label} />
|
||||||
|
</span>
|
||||||
|
{/if}
|
@ -51,7 +51,8 @@
|
|||||||
viewlet,
|
viewlet,
|
||||||
viewOptions,
|
viewOptions,
|
||||||
viewOptionsConfig: viewlet.viewOptions?.other,
|
viewOptionsConfig: viewlet.viewOptions?.other,
|
||||||
enableChecking: false
|
enableChecking: false,
|
||||||
|
prefferedSorting: 'createdOn'
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
29
plugins/love-resources/src/components/PanelControlBar.svelte
Normal file
29
plugins/love-resources/src/components/PanelControlBar.svelte
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<!--
|
||||||
|
// 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { MeetingMinutes } from '@hcengineering/love'
|
||||||
|
|
||||||
|
import ControlBar from './ControlBar.svelte'
|
||||||
|
import { currentRoom, currentMeetingMinutes } from '../stores'
|
||||||
|
|
||||||
|
export let object: MeetingMinutes
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if $currentRoom && $currentMeetingMinutes?._id === object._id}
|
||||||
|
<div class="flex-grow flex-shrink">
|
||||||
|
<ControlBar room={$currentRoom} />
|
||||||
|
</div>
|
||||||
|
{/if}
|
@ -50,6 +50,7 @@
|
|||||||
import ParticipantView from './ParticipantView.svelte'
|
import ParticipantView from './ParticipantView.svelte'
|
||||||
|
|
||||||
export let withVideo: boolean
|
export let withVideo: boolean
|
||||||
|
export let canMaximize: boolean = true
|
||||||
export let room: TypeRoom
|
export let room: TypeRoom
|
||||||
|
|
||||||
interface ParticipantData {
|
interface ParticipantData {
|
||||||
@ -432,7 +433,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{#if $currentRoom}
|
{#if $currentRoom}
|
||||||
<ControlBar room={$currentRoom} fullScreen={$isFullScreen} {onFullScreen} />
|
<ControlBar room={$currentRoom} fullScreen={$isFullScreen} {onFullScreen} {canMaximize} />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -38,6 +38,6 @@
|
|||||||
padding="0"
|
padding="0"
|
||||||
on:close={() => dispatch('close')}
|
on:close={() => dispatch('close')}
|
||||||
>
|
>
|
||||||
<RoomComponent withVideo={$currentRoom.type === RoomType.Video} room={$currentRoom} />
|
<RoomComponent withVideo={$currentRoom.type === RoomType.Video} room={$currentRoom} canMaximize={false} />
|
||||||
</Modal>
|
</Modal>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Person, PersonAccount } from '@hcengineering/contact'
|
import { Person, PersonAccount } from '@hcengineering/contact'
|
||||||
import { personByIdStore, UserInfo } from '@hcengineering/contact-resources'
|
import { personByIdStore, UserInfo } from '@hcengineering/contact-resources'
|
||||||
import { IdMap, getCurrentAccount } from '@hcengineering/core'
|
import { IdMap, getCurrentAccount, Ref, Class, Doc } from '@hcengineering/core'
|
||||||
import ui, {
|
import ui, {
|
||||||
ModernButton,
|
ModernButton,
|
||||||
SplitButton,
|
SplitButton,
|
||||||
@ -23,12 +23,12 @@
|
|||||||
IconUpOutline,
|
IconUpOutline,
|
||||||
Label,
|
Label,
|
||||||
eventToHTMLElement,
|
eventToHTMLElement,
|
||||||
getCurrentLocation,
|
Location,
|
||||||
location,
|
location,
|
||||||
navigate,
|
navigate,
|
||||||
showPopup,
|
showPopup,
|
||||||
Scroller,
|
Scroller,
|
||||||
closePanel
|
panelstore
|
||||||
} from '@hcengineering/ui'
|
} from '@hcengineering/ui'
|
||||||
import {
|
import {
|
||||||
ParticipantInfo,
|
ParticipantInfo,
|
||||||
@ -37,11 +37,14 @@
|
|||||||
isOffice,
|
isOffice,
|
||||||
loveId,
|
loveId,
|
||||||
roomAccessIcon,
|
roomAccessIcon,
|
||||||
roomAccessLabel
|
roomAccessLabel,
|
||||||
|
MeetingMinutes
|
||||||
} from '@hcengineering/love'
|
} from '@hcengineering/love'
|
||||||
import { createEventDispatcher } from 'svelte'
|
import { createEventDispatcher } from 'svelte'
|
||||||
|
import { getObjectLinkFragment } from '@hcengineering/view-resources'
|
||||||
|
import { getClient } from '@hcengineering/presentation'
|
||||||
import love from '../plugin'
|
import love from '../plugin'
|
||||||
import { currentRoom, infos, invites, myInfo, myOffice, myRequests } from '../stores'
|
import { currentRoom, infos, invites, myInfo, myOffice, myRequests, currentMeetingMinutes } from '../stores'
|
||||||
import {
|
import {
|
||||||
getRoomName,
|
getRoomName,
|
||||||
isCameraEnabled,
|
isCameraEnabled,
|
||||||
@ -58,9 +61,11 @@
|
|||||||
import CamSettingPopup from './CamSettingPopup.svelte'
|
import CamSettingPopup from './CamSettingPopup.svelte'
|
||||||
import MicSettingPopup from './MicSettingPopup.svelte'
|
import MicSettingPopup from './MicSettingPopup.svelte'
|
||||||
import RoomAccessPopup from './RoomAccessPopup.svelte'
|
import RoomAccessPopup from './RoomAccessPopup.svelte'
|
||||||
|
import view from '@hcengineering/view'
|
||||||
|
|
||||||
export let room: Room
|
export let room: Room
|
||||||
|
|
||||||
|
const client = getClient()
|
||||||
function getPerson (info: ParticipantInfo | undefined, employees: IdMap<Person>): Person | undefined {
|
function getPerson (info: ParticipantInfo | undefined, employees: IdMap<Person>): Person | undefined {
|
||||||
if (info !== undefined) {
|
if (info !== undefined) {
|
||||||
return employees.get(info.person)
|
return employees.get(info.person)
|
||||||
@ -104,12 +109,20 @@
|
|||||||
dispatch('close')
|
dispatch('close')
|
||||||
}
|
}
|
||||||
|
|
||||||
function back (): void {
|
async function back (): Promise<void> {
|
||||||
closePanel()
|
const meetingMinutes = $currentMeetingMinutes
|
||||||
const loc = getCurrentLocation()
|
if (meetingMinutes !== undefined) {
|
||||||
loc.path[2] = loveId
|
const hierarchy = client.getHierarchy()
|
||||||
loc.path.length = 3
|
const panelComponent = hierarchy.classHierarchyMixin(
|
||||||
navigate(loc)
|
meetingMinutes._class as Ref<Class<Doc>>,
|
||||||
|
view.mixin.ObjectPanel
|
||||||
|
)
|
||||||
|
const comp = panelComponent?.component ?? view.component.EditDoc
|
||||||
|
const loc = await getObjectLinkFragment(hierarchy, meetingMinutes, {}, comp)
|
||||||
|
loc.path[2] = loveId
|
||||||
|
loc.path.length = 3
|
||||||
|
navigate(loc)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function micSettings (e: MouseEvent): void {
|
function micSettings (e: MouseEvent): void {
|
||||||
@ -129,6 +142,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const me = (getCurrentAccount() as PersonAccount).person
|
const me = (getCurrentAccount() as PersonAccount).person
|
||||||
|
function canGoBack (joined: boolean, location: Location, meetingMinutes?: MeetingMinutes): boolean {
|
||||||
|
if (!joined) return false
|
||||||
|
if (location.path[2] !== loveId) return true
|
||||||
|
if (meetingMinutes === undefined) return false
|
||||||
|
|
||||||
|
const panel = $panelstore.panel
|
||||||
|
const { _id } = panel ?? {}
|
||||||
|
|
||||||
|
return _id !== meetingMinutes._id
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="antiPopup room-popup">
|
<div class="antiPopup room-popup">
|
||||||
@ -215,7 +238,7 @@
|
|||||||
on:click={connect}
|
on:click={connect}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $location.path[2] !== loveId}
|
{#if canGoBack(joined, $location, $currentMeetingMinutes)}
|
||||||
<ModernButton icon={IconArrowLeft} label={ui.string.Back} kind={'secondary'} size={'large'} on:click={back} />
|
<ModernButton icon={IconArrowLeft} label={ui.string.Back} kind={'secondary'} size={'large'} on:click={back} />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
53
plugins/love-resources/src/components/RoomPresenter.svelte
Normal file
53
plugins/love-resources/src/components/RoomPresenter.svelte
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
<!--
|
||||||
|
// 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.
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
import love, { Room } from '@hcengineering/love'
|
||||||
|
import { WithLookup } from '@hcengineering/core'
|
||||||
|
import { ObjectPresenterType } from '@hcengineering/view'
|
||||||
|
import { getEmbeddedLabel } from '@hcengineering/platform'
|
||||||
|
import { DocNavLink, ObjectMention } from '@hcengineering/view-resources'
|
||||||
|
import { tooltip, Icon } from '@hcengineering/ui'
|
||||||
|
|
||||||
|
export let value: WithLookup<Room>
|
||||||
|
export let inline: boolean = false
|
||||||
|
export let disabled: boolean = false
|
||||||
|
export let accent: boolean = false
|
||||||
|
export let noUnderline: boolean = false
|
||||||
|
export let shouldShowAvatar = true
|
||||||
|
export let type: ObjectPresenterType = 'link'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if value}
|
||||||
|
{#if inline}
|
||||||
|
<ObjectMention object={value} {disabled} {accent} {noUnderline} />
|
||||||
|
{:else if type === 'link'}
|
||||||
|
<DocNavLink object={value} {disabled} {accent} {noUnderline}>
|
||||||
|
<div class="flex-presenter" use:tooltip={{ label: getEmbeddedLabel(value.name) }}>
|
||||||
|
{#if shouldShowAvatar}
|
||||||
|
<div class="icon">
|
||||||
|
<Icon icon={love.icon.Love} size={'small'} />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<div class="label nowrap flex flex-gap-2" class:no-underline={noUnderline || disabled} class:fs-bold={accent}>
|
||||||
|
<span>{value.name}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DocNavLink>
|
||||||
|
{:else if type === 'text'}
|
||||||
|
<span class="overflow-label" use:tooltip={{ label: getEmbeddedLabel(value.name) }}>
|
||||||
|
{value.name}
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
@ -24,7 +24,7 @@
|
|||||||
import { get } from 'svelte/store'
|
import { get } from 'svelte/store'
|
||||||
|
|
||||||
import love from '../plugin'
|
import love from '../plugin'
|
||||||
import { myInfo, selectedRoomPlace, currentRoom, meetingMinutesStore } from '../stores'
|
import { myInfo, selectedRoomPlace, currentRoom, currentMeetingMinutes } from '../stores'
|
||||||
import { getRoomLabel, lk } from '../utils'
|
import { getRoomLabel, lk } from '../utils'
|
||||||
import PersonActionPopup from './PersonActionPopup.svelte'
|
import PersonActionPopup from './PersonActionPopup.svelte'
|
||||||
import RoomLanguage from './RoomLanguage.svelte'
|
import RoomLanguage from './RoomLanguage.svelte'
|
||||||
@ -64,23 +64,32 @@
|
|||||||
hovered = false
|
hovered = false
|
||||||
}
|
}
|
||||||
|
|
||||||
async function clickHandler (e: MouseEvent, x: number, y: number, person: Person | undefined): Promise<void> {
|
async function openRoom (x: number, y: number): Promise<void> {
|
||||||
|
const client = getClient()
|
||||||
|
const hierarchy = client.getHierarchy()
|
||||||
|
if ($currentRoom?._id === room._id) {
|
||||||
|
const sid = await lk.getSid()
|
||||||
|
const meetingMinutes =
|
||||||
|
get(currentMeetingMinutes) ?? (await client.findOne(love.class.MeetingMinutes, { sid, attachedTo: room._id }))
|
||||||
|
if (meetingMinutes === undefined) {
|
||||||
|
await openDoc(hierarchy, room)
|
||||||
|
} else {
|
||||||
|
await openDoc(hierarchy, meetingMinutes)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
selectedRoomPlace.set({ _id: room._id, x, y })
|
||||||
|
await openDoc(hierarchy, room)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function placeClickHandler (e: MouseEvent, x: number, y: number, person: Person | undefined): Promise<void> {
|
||||||
|
e.stopPropagation()
|
||||||
|
e.preventDefault()
|
||||||
if (person !== undefined) {
|
if (person !== undefined) {
|
||||||
if (room._id === $myInfo?.room || $myInfo === undefined) return
|
if (room._id === $myInfo?.room || $myInfo === undefined) return
|
||||||
showPopup(PersonActionPopup, { room, person: person._id }, eventToHTMLElement(e))
|
showPopup(PersonActionPopup, { room, person: person._id }, eventToHTMLElement(e))
|
||||||
} else {
|
} else {
|
||||||
const client = getClient()
|
await openRoom(x, y)
|
||||||
const hierarchy = client.getHierarchy()
|
|
||||||
if ($currentRoom?._id === room._id) {
|
|
||||||
const sid = await lk.getSid()
|
|
||||||
const meetingMinutes =
|
|
||||||
get(meetingMinutesStore) ?? (await client.findOne(love.class.MeetingMinutes, { sid, attachedTo: room._id }))
|
|
||||||
if (meetingMinutes === undefined) return
|
|
||||||
await openDoc(hierarchy, meetingMinutes)
|
|
||||||
} else {
|
|
||||||
selectedRoomPlace.set({ _id: room._id, x, y })
|
|
||||||
await openDoc(hierarchy, room)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,6 +130,10 @@
|
|||||||
}
|
}
|
||||||
return init
|
return init
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function handleClick (): Promise<void> {
|
||||||
|
await openRoom(0, 0)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||||
@ -141,6 +154,7 @@
|
|||||||
on:mouseover|stopPropagation
|
on:mouseover|stopPropagation
|
||||||
on:mouseenter|stopPropagation={mouseEnter}
|
on:mouseenter|stopPropagation={mouseEnter}
|
||||||
on:mouseleave|stopPropagation={mouseLeave}
|
on:mouseleave|stopPropagation={mouseLeave}
|
||||||
|
on:click|stopPropagation={handleClick}
|
||||||
>
|
>
|
||||||
{#each new Array(room.height) as _, y}
|
{#each new Array(room.height) as _, y}
|
||||||
{#each new Array(room.width + extraRow) as _, x}
|
{#each new Array(room.width + extraRow) as _, x}
|
||||||
@ -162,7 +176,7 @@
|
|||||||
hoveredRoomY = undefined
|
hoveredRoomY = undefined
|
||||||
}}
|
}}
|
||||||
on:click={(e) => {
|
on:click={(e) => {
|
||||||
clickHandler(e, x, y, person)
|
placeClickHandler(e, x, y, person)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{#if personInfo}
|
{#if personInfo}
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
import love from '../../plugin'
|
import love from '../../plugin'
|
||||||
import VideoTab from './VideoTab.svelte'
|
import VideoTab from './VideoTab.svelte'
|
||||||
import { isCurrentInstanceConnected, lk } from '../../utils'
|
import { isCurrentInstanceConnected, lk } from '../../utils'
|
||||||
import { currentRoom, meetingMinutesStore } from '../../stores'
|
import { currentRoom, currentMeetingMinutes } from '../../stores'
|
||||||
import ChatTab from './ChatTab.svelte'
|
import ChatTab from './ChatTab.svelte'
|
||||||
import TranscriptionTab from './TranscriptionTab.svelte'
|
import TranscriptionTab from './TranscriptionTab.svelte'
|
||||||
|
|
||||||
@ -60,7 +60,9 @@
|
|||||||
$: if (sid != null && room !== undefined) {
|
$: if (sid != null && room !== undefined) {
|
||||||
meetingQuery.query(love.class.MeetingMinutes, { sid, attachedTo: room._id }, async (res) => {
|
meetingQuery.query(love.class.MeetingMinutes, { sid, attachedTo: room._id }, async (res) => {
|
||||||
meetingMinutes = res[0]
|
meetingMinutes = res[0]
|
||||||
meetingMinutesStore.set(meetingMinutes)
|
if (meetingMinutes) {
|
||||||
|
currentMeetingMinutes.set(meetingMinutes)
|
||||||
|
}
|
||||||
isMeetingMinutesLoaded = true
|
isMeetingMinutesLoaded = true
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
@ -18,6 +18,10 @@ import EditRoom from './components/EditRoom.svelte'
|
|||||||
import FloorAttributePresenter from './components/FloorAttributePresenter.svelte'
|
import FloorAttributePresenter from './components/FloorAttributePresenter.svelte'
|
||||||
import FloorView from './components/FloorView.svelte'
|
import FloorView from './components/FloorView.svelte'
|
||||||
import MeetingMinutesTable from './components/MeetingMinutesTable.svelte'
|
import MeetingMinutesTable from './components/MeetingMinutesTable.svelte'
|
||||||
|
import PanelControlBar from './components/PanelControlBar.svelte'
|
||||||
|
import RoomPresenter from './components/RoomPresenter.svelte'
|
||||||
|
import MeetingMinutesDocEditor from './components/MeetingMinutesDocEditor.svelte'
|
||||||
|
import MeetingMinutesStatusPresenter from './components/MeetingMinutesStatusPresenter.svelte'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
copyGuestLink,
|
copyGuestLink,
|
||||||
@ -49,7 +53,11 @@ export default async (): Promise<Resources> => ({
|
|||||||
EditRoom,
|
EditRoom,
|
||||||
FloorAttributePresenter,
|
FloorAttributePresenter,
|
||||||
FloorView,
|
FloorView,
|
||||||
MeetingMinutesTable
|
MeetingMinutesTable,
|
||||||
|
PanelControlBar,
|
||||||
|
RoomPresenter,
|
||||||
|
MeetingMinutesDocEditor,
|
||||||
|
MeetingMinutesStatusPresenter
|
||||||
},
|
},
|
||||||
function: {
|
function: {
|
||||||
CreateMeeting: createMeeting,
|
CreateMeeting: createMeeting,
|
||||||
|
@ -25,12 +25,16 @@ export default mergeIds(loveId, love, {
|
|||||||
MeetingData: '' as AnyComponent,
|
MeetingData: '' as AnyComponent,
|
||||||
EditMeetingData: '' as AnyComponent,
|
EditMeetingData: '' as AnyComponent,
|
||||||
MeetingMinutesPresenter: '' as AnyComponent,
|
MeetingMinutesPresenter: '' as AnyComponent,
|
||||||
|
RoomPresenter: '' as AnyComponent,
|
||||||
MeetingMinutesSection: '' as AnyComponent,
|
MeetingMinutesSection: '' as AnyComponent,
|
||||||
EditMeetingMinutes: '' as AnyComponent,
|
EditMeetingMinutes: '' as AnyComponent,
|
||||||
EditRoom: '' as AnyComponent,
|
EditRoom: '' as AnyComponent,
|
||||||
FloorAttributePresenter: '' as AnyComponent,
|
FloorAttributePresenter: '' as AnyComponent,
|
||||||
MeetingMinutesTable: '' as AnyComponent,
|
MeetingMinutesTable: '' as AnyComponent,
|
||||||
FloorView: '' as AnyComponent
|
FloorView: '' as AnyComponent,
|
||||||
|
PanelControlBar: '' as AnyComponent,
|
||||||
|
MeetingMinutesDocEditor: '' as AnyComponent,
|
||||||
|
MeetingMinutesStatusPresenter: '' as AnyComponent
|
||||||
},
|
},
|
||||||
function: {
|
function: {
|
||||||
CreateMeeting: '' as Resource<DocCreateFunction>,
|
CreateMeeting: '' as Resource<DocCreateFunction>,
|
||||||
|
@ -60,7 +60,7 @@ export const activeInvites = derived(invites, (val) => {
|
|||||||
export const myPreferences = writable<DevicesPreference | undefined>()
|
export const myPreferences = writable<DevicesPreference | undefined>()
|
||||||
export let $myPreferences: DevicesPreference | undefined
|
export let $myPreferences: DevicesPreference | undefined
|
||||||
|
|
||||||
export const meetingMinutesStore = writable<MeetingMinutes | undefined>(undefined)
|
export const currentMeetingMinutes = writable<MeetingMinutes | undefined>(undefined)
|
||||||
export const selectedRoomPlace = writable<{ _id: Ref<Room>, x: number, y: number } | undefined>(undefined)
|
export const selectedRoomPlace = writable<{ _id: Ref<Room>, x: number, y: number } | undefined>(undefined)
|
||||||
|
|
||||||
function filterParticipantInfo (value: ParticipantInfo[]): ParticipantInfo[] {
|
function filterParticipantInfo (value: ParticipantInfo[]): ParticipantInfo[] {
|
||||||
|
@ -30,7 +30,8 @@ import {
|
|||||||
RoomType,
|
RoomType,
|
||||||
TranscriptionStatus,
|
TranscriptionStatus,
|
||||||
type RoomMetadata,
|
type RoomMetadata,
|
||||||
type MeetingMinutes
|
type MeetingMinutes,
|
||||||
|
MeetingStatus
|
||||||
} from '@hcengineering/love'
|
} from '@hcengineering/love'
|
||||||
import { getEmbeddedLabel, getMetadata, getResource, type IntlString } from '@hcengineering/platform'
|
import { getEmbeddedLabel, getMetadata, getResource, type IntlString } from '@hcengineering/platform'
|
||||||
import presentation, {
|
import presentation, {
|
||||||
@ -39,7 +40,14 @@ import presentation, {
|
|||||||
type DocCreatePhase,
|
type DocCreatePhase,
|
||||||
getClient
|
getClient
|
||||||
} from '@hcengineering/presentation'
|
} from '@hcengineering/presentation'
|
||||||
import { type DropdownTextItem, getCurrentLocation, navigate, showPopup } from '@hcengineering/ui'
|
import {
|
||||||
|
type DropdownTextItem,
|
||||||
|
getCurrentLocation,
|
||||||
|
navigate,
|
||||||
|
showPopup,
|
||||||
|
panelstore,
|
||||||
|
closePanel
|
||||||
|
} from '@hcengineering/ui'
|
||||||
import { isKrispNoiseFilterSupported, KrispNoiseFilter } from '@livekit/krisp-noise-filter'
|
import { isKrispNoiseFilterSupported, KrispNoiseFilter } from '@livekit/krisp-noise-filter'
|
||||||
import { BackgroundBlur, type BackgroundOptions, type ProcessorWrapper } from '@livekit/track-processors'
|
import { BackgroundBlur, type BackgroundOptions, type ProcessorWrapper } from '@livekit/track-processors'
|
||||||
import {
|
import {
|
||||||
@ -70,10 +78,11 @@ import {
|
|||||||
import { type Widget, type WidgetTab } from '@hcengineering/workbench'
|
import { type Widget, type WidgetTab } from '@hcengineering/workbench'
|
||||||
import view from '@hcengineering/view'
|
import view from '@hcengineering/view'
|
||||||
import chunter from '@hcengineering/chunter'
|
import chunter from '@hcengineering/chunter'
|
||||||
|
import { openDoc } from '@hcengineering/view-resources'
|
||||||
|
|
||||||
import { sendMessage } from './broadcast'
|
import { sendMessage } from './broadcast'
|
||||||
import love from './plugin'
|
import love from './plugin'
|
||||||
import { $myPreferences, meetingMinutesStore, currentRoom } from './stores'
|
import { $myPreferences, currentRoom, currentMeetingMinutes, selectedRoomPlace } from './stores'
|
||||||
import RoomSettingsPopup from './components/RoomSettingsPopup.svelte'
|
import RoomSettingsPopup from './components/RoomSettingsPopup.svelte'
|
||||||
|
|
||||||
export const selectedCamId = 'selectedDevice_cam'
|
export const selectedCamId = 'selectedDevice_cam'
|
||||||
@ -444,7 +453,6 @@ export async function disconnect (): Promise<void> {
|
|||||||
isMicEnabled.set(false)
|
isMicEnabled.set(false)
|
||||||
isCameraEnabled.set(false)
|
isCameraEnabled.set(false)
|
||||||
isSharingEnabled.set(false)
|
isSharingEnabled.set(false)
|
||||||
meetingMinutesStore.set(undefined)
|
|
||||||
sendMessage({ type: 'mic', value: false })
|
sendMessage({ type: 'mic', value: false })
|
||||||
sendMessage({ type: 'cam', value: false })
|
sendMessage({ type: 'cam', value: false })
|
||||||
sendMessage({ type: 'share', value: false })
|
sendMessage({ type: 'share', value: false })
|
||||||
@ -463,6 +471,22 @@ export async function leaveRoom (ownInfo: ParticipantInfo | undefined, ownOffice
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
await disconnect()
|
await disconnect()
|
||||||
|
closeMeetingMinutes()
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeMeetingMinutes (): void {
|
||||||
|
const loc = getCurrentLocation()
|
||||||
|
|
||||||
|
if (loc.path[2] === loveId) {
|
||||||
|
const meetingMinutes = get(currentMeetingMinutes)
|
||||||
|
const panel = get(panelstore).panel
|
||||||
|
const { _id } = panel ?? {}
|
||||||
|
|
||||||
|
if (_id !== undefined && meetingMinutes !== undefined && _id === meetingMinutes._id) {
|
||||||
|
closePanel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currentMeetingMinutes.set(undefined)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function setCam (value: boolean): Promise<void> {
|
export async function setCam (value: boolean): Promise<void> {
|
||||||
@ -593,7 +617,7 @@ async function connectLK (currentPerson: Person, room: Room): Promise<void> {
|
|||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createMeetingMinutes (room: Room): Promise<void> {
|
async function openMeetingMinutes (room: Room): Promise<void> {
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
const sid = await lk.getSid()
|
const sid = await lk.getSid()
|
||||||
|
|
||||||
@ -601,7 +625,17 @@ async function createMeetingMinutes (room: Room): Promise<void> {
|
|||||||
const doc = await client.findOne(love.class.MeetingMinutes, { sid })
|
const doc = await client.findOne(love.class.MeetingMinutes, { sid })
|
||||||
|
|
||||||
if (doc === undefined) {
|
if (doc === undefined) {
|
||||||
const dateStr = new Date().toISOString().replace('T', ' ').slice(0, 19)
|
const date = new Date()
|
||||||
|
.toLocaleDateString('en-GB', {
|
||||||
|
day: 'numeric',
|
||||||
|
month: 'long',
|
||||||
|
year: 'numeric',
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit',
|
||||||
|
hour12: false,
|
||||||
|
timeZone: 'UTC'
|
||||||
|
})
|
||||||
|
.replace(',', ' at')
|
||||||
const _id = generateId<MeetingMinutes>()
|
const _id = generateId<MeetingMinutes>()
|
||||||
const newDoc: MeetingMinutes = {
|
const newDoc: MeetingMinutes = {
|
||||||
_id,
|
_id,
|
||||||
@ -611,24 +645,35 @@ async function createMeetingMinutes (room: Room): Promise<void> {
|
|||||||
attachedToClass: room._class,
|
attachedToClass: room._class,
|
||||||
collection: 'meetings',
|
collection: 'meetings',
|
||||||
space: core.space.Workspace,
|
space: core.space.Workspace,
|
||||||
title: room.name + ' ' + dateStr,
|
title: `${room.name} ${date}`,
|
||||||
description: makeCollaborativeDoc(_id, 'description'),
|
description: makeCollaborativeDoc(_id, 'description'),
|
||||||
|
status: MeetingStatus.Active,
|
||||||
modifiedBy: getCurrentAccount()._id,
|
modifiedBy: getCurrentAccount()._id,
|
||||||
modifiedOn: Date.now()
|
modifiedOn: Date.now()
|
||||||
}
|
}
|
||||||
|
|
||||||
await client.addCollection(
|
await client.addCollection(
|
||||||
love.class.MeetingMinutes,
|
love.class.MeetingMinutes,
|
||||||
core.space.Workspace,
|
core.space.Workspace,
|
||||||
room._id,
|
room._id,
|
||||||
room._class,
|
room._class,
|
||||||
'meetings',
|
'meetings',
|
||||||
{ sid, title: newDoc.title, description: newDoc.description },
|
{ sid, title: newDoc.title, description: newDoc.description, status: newDoc.status },
|
||||||
_id
|
_id
|
||||||
)
|
)
|
||||||
meetingMinutesStore.set(newDoc)
|
currentMeetingMinutes.set(newDoc)
|
||||||
|
const loc = getCurrentLocation()
|
||||||
|
if (loc.path[2] === loveId) {
|
||||||
|
await openDoc(client.getHierarchy(), newDoc)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
meetingMinutesStore.set(doc)
|
currentMeetingMinutes.set(doc)
|
||||||
|
const loc = getCurrentLocation()
|
||||||
|
if (loc.path[2] === loveId) {
|
||||||
|
await openDoc(client.getHierarchy(), doc)
|
||||||
|
}
|
||||||
|
if (doc.status !== MeetingStatus.Active) {
|
||||||
|
void client.update(doc, { status: MeetingStatus.Active, meetingEnd: undefined })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -643,7 +688,8 @@ export async function connectRoom (
|
|||||||
await disconnect()
|
await disconnect()
|
||||||
await moveToRoom(x, y, currentInfo, currentPerson, room, getMetadata(presentation.metadata.SessionId) ?? null)
|
await moveToRoom(x, y, currentInfo, currentPerson, room, getMetadata(presentation.metadata.SessionId) ?? null)
|
||||||
await connectLK(currentPerson, room)
|
await connectLK(currentPerson, room)
|
||||||
await createMeetingMinutes(room)
|
selectedRoomPlace.set(undefined)
|
||||||
|
await openMeetingMinutes(room)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const joinRequest: Ref<JoinRequest> | undefined = undefined
|
export const joinRequest: Ref<JoinRequest> | undefined = undefined
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Event } from '@hcengineering/calendar'
|
import { Event } from '@hcengineering/calendar'
|
||||||
import { Person } from '@hcengineering/contact'
|
import { Person } from '@hcengineering/contact'
|
||||||
import { AttachedDoc, Class, CollaborativeDoc, Doc, Mixin, Ref } from '@hcengineering/core'
|
import { AttachedDoc, Class, CollaborativeDoc, Doc, Mixin, Ref, Timestamp } from '@hcengineering/core'
|
||||||
import { Drive } from '@hcengineering/drive'
|
import { Drive } from '@hcengineering/drive'
|
||||||
import { NotificationType } from '@hcengineering/notification'
|
import { NotificationType } from '@hcengineering/notification'
|
||||||
import { Asset, IntlString, Metadata, Plugin, plugin } from '@hcengineering/platform'
|
import { Asset, IntlString, Metadata, Plugin, plugin } from '@hcengineering/platform'
|
||||||
@ -105,6 +105,7 @@ export interface Room extends Doc {
|
|||||||
description: CollaborativeDoc
|
description: CollaborativeDoc
|
||||||
attachments?: number
|
attachments?: number
|
||||||
meetings?: number
|
meetings?: number
|
||||||
|
messages?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Office extends Room {
|
export interface Office extends Room {
|
||||||
@ -158,12 +159,22 @@ export interface DevicesPreference extends Preference {
|
|||||||
camEnabled: boolean
|
camEnabled: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum MeetingStatus {
|
||||||
|
Active,
|
||||||
|
Finished
|
||||||
|
}
|
||||||
|
|
||||||
export interface MeetingMinutes extends AttachedDoc {
|
export interface MeetingMinutes extends AttachedDoc {
|
||||||
sid: string
|
sid: string
|
||||||
|
|
||||||
title: string
|
title: string
|
||||||
|
description: CollaborativeDoc
|
||||||
|
|
||||||
|
status: MeetingStatus
|
||||||
|
meetingEnd?: Timestamp
|
||||||
|
|
||||||
transcription?: number
|
transcription?: number
|
||||||
messages?: number
|
messages?: number
|
||||||
description: CollaborativeDoc
|
|
||||||
attachments?: number
|
attachments?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,10 +216,16 @@ const love = plugin(loveId, {
|
|||||||
Transcription: '' as IntlString,
|
Transcription: '' as IntlString,
|
||||||
StartWithTranscription: '' as IntlString,
|
StartWithTranscription: '' as IntlString,
|
||||||
MeetingMinutes: '' as IntlString,
|
MeetingMinutes: '' as IntlString,
|
||||||
|
MeetingsMinutes: '' as IntlString,
|
||||||
StartMeeting: '' as IntlString,
|
StartMeeting: '' as IntlString,
|
||||||
Video: '' as IntlString,
|
Video: '' as IntlString,
|
||||||
NoMeetingMinutes: '' as IntlString,
|
NoMeetingMinutes: '' as IntlString,
|
||||||
JoinMeeting: '' as IntlString
|
JoinMeeting: '' as IntlString,
|
||||||
|
MeetingStart: '' as IntlString,
|
||||||
|
MeetingEnd: '' as IntlString,
|
||||||
|
Status: '' as IntlString,
|
||||||
|
Active: '' as IntlString,
|
||||||
|
Finished: '' as IntlString
|
||||||
},
|
},
|
||||||
ids: {
|
ids: {
|
||||||
MainFloor: '' as Ref<Floor>,
|
MainFloor: '' as Ref<Floor>,
|
||||||
@ -254,6 +271,7 @@ const love = plugin(loveId, {
|
|||||||
},
|
},
|
||||||
viewlet: {
|
viewlet: {
|
||||||
TableMeetingMinutes: '' as Ref<Viewlet>,
|
TableMeetingMinutes: '' as Ref<Viewlet>,
|
||||||
|
TableMeetingMinutesEmbedded: '' as Ref<Viewlet>,
|
||||||
MeetingMinutesDescriptor: '' as Ref<ViewletDescriptor>,
|
MeetingMinutesDescriptor: '' as Ref<ViewletDescriptor>,
|
||||||
FloorDescriptor: '' as Ref<ViewletDescriptor>,
|
FloorDescriptor: '' as Ref<ViewletDescriptor>,
|
||||||
Floor: '' as Ref<Viewlet>,
|
Floor: '' as Ref<Viewlet>,
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
import { Component, showPanel } from '@hcengineering/ui'
|
import { Component, showPanel } from '@hcengineering/ui'
|
||||||
import view from '@hcengineering/view'
|
import view from '@hcengineering/view'
|
||||||
import time from '../plugin'
|
import time from '../plugin'
|
||||||
import { getObjectLinkId } from '@hcengineering/view-resources'
|
import { DocReferencePresenter, getObjectLinkId } from '@hcengineering/view-resources'
|
||||||
|
|
||||||
export let todo: ToDo
|
export let todo: ToDo
|
||||||
export let kind: 'default' | 'todo-line' = 'default'
|
export let kind: 'default' | 'todo-line' = 'default'
|
||||||
@ -50,16 +50,22 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if presenter?.presenter && doc}
|
{#if doc}
|
||||||
{#if kind === 'default'}
|
{#if presenter?.presenter}
|
||||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
{#if kind === 'default'}
|
||||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||||
<div class="cursor-pointer clear-mins" on:click={click}>
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
<Component is={presenter.presenter} props={{ value: doc, withoutSpace }} />
|
<div class="cursor-pointer clear-mins" on:click={click}>
|
||||||
</div>
|
<Component is={presenter.presenter} props={{ value: doc, withoutSpace }} />
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<Component is={presenter.presenter} props={{ value: doc, withoutSpace }} on:click={click}>
|
||||||
|
<slot />
|
||||||
|
</Component>
|
||||||
|
{/if}
|
||||||
{:else}
|
{:else}
|
||||||
<Component is={presenter.presenter} props={{ value: doc, withoutSpace }} on:click={click}>
|
<DocReferencePresenter value={doc} on:click={click}>
|
||||||
<slot />
|
<slot />
|
||||||
</Component>
|
</DocReferencePresenter>
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -155,9 +155,24 @@
|
|||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getPanelFooter (
|
||||||
|
_class: Ref<Class<Doc>>,
|
||||||
|
object?: Doc
|
||||||
|
): { footer: AnyComponent, props?: Record<string, any> } | undefined {
|
||||||
|
if (object !== undefined) {
|
||||||
|
const footer = hierarchy.findClassOrMixinMixin(object, view.mixin.ObjectPanelFooter)
|
||||||
|
if (footer !== undefined) {
|
||||||
|
return { footer: footer.editor, props: footer.props }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
let mainEditor: MixinEditor | undefined
|
let mainEditor: MixinEditor | undefined
|
||||||
|
|
||||||
$: editorFooter = getEditorFooter(_class, object)
|
$: editorFooter = getEditorFooter(_class, object)
|
||||||
|
$: panelFooter = getPanelFooter(_class, object)
|
||||||
|
|
||||||
const getEditorOrDefault = reduceCalls(async function (_class: Ref<Class<Doc>>, _id?: Ref<Doc>): Promise<void> {
|
const getEditorOrDefault = reduceCalls(async function (_class: Ref<Class<Doc>>, _id?: Ref<Doc>): Promise<void> {
|
||||||
if (objectId === undefined) return
|
if (objectId === undefined) return
|
||||||
@ -341,5 +356,11 @@
|
|||||||
<Component is={editorFooter.footer} props={{ object, _class, ...editorFooter.props, readonly }} />
|
<Component is={editorFooter.footer} props={{ object, _class, ...editorFooter.props, readonly }} />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
<svelte:fragment slot="panel-footer">
|
||||||
|
{#if panelFooter}
|
||||||
|
<Component is={panelFooter.footer} props={{ object, _class, ...panelFooter.props, readonly }} />
|
||||||
|
{/if}
|
||||||
|
</svelte:fragment>
|
||||||
</Panel>
|
</Panel>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
export let enableChecking = true
|
export let enableChecking = true
|
||||||
export let tableId: string | undefined = undefined
|
export let tableId: string | undefined = undefined
|
||||||
export let fade: FadeOptions = tableSP
|
export let fade: FadeOptions = tableSP
|
||||||
|
export let prefferedSorting: string = 'modifiedOn'
|
||||||
|
|
||||||
// If defined, will show a number of dummy items before real data will appear.
|
// If defined, will show a number of dummy items before real data will appear.
|
||||||
export let loadingProps: LoadingProps | undefined = undefined
|
export let loadingProps: LoadingProps | undefined = undefined
|
||||||
@ -55,11 +56,9 @@
|
|||||||
// Search config
|
// Search config
|
||||||
const _config = config
|
const _config = config
|
||||||
|
|
||||||
let prefferedSorting: string = 'modifiedOn'
|
|
||||||
|
|
||||||
function updateConfig (config: Array<BuildModelKey | string>, search?: string): void {
|
function updateConfig (config: Array<BuildModelKey | string>, search?: string): void {
|
||||||
const useSearch = search !== '' && search != null
|
const useSearch = search !== '' && search != null
|
||||||
prefferedSorting = !useSearch ? 'modifiedOn' : '#score'
|
prefferedSorting = !useSearch ? prefferedSorting : '#score'
|
||||||
}
|
}
|
||||||
|
|
||||||
$: updateConfig(config, query.$search)
|
$: updateConfig(config, query.$search)
|
||||||
|
@ -27,7 +27,9 @@
|
|||||||
{#if kind === 'link'}
|
{#if kind === 'link'}
|
||||||
<Button {kind} {size} {justify} {width}>
|
<Button {kind} {size} {justify} {width}>
|
||||||
<svelte:fragment slot="content">
|
<svelte:fragment slot="content">
|
||||||
<TimeSince {value} />
|
{#if value != null}
|
||||||
|
<TimeSince {value} />
|
||||||
|
{/if}
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
</Button>
|
</Button>
|
||||||
{:else}
|
{:else}
|
||||||
|
@ -91,6 +91,7 @@ const view = plugin(viewId, {
|
|||||||
ObjectPresenter: '' as Ref<Mixin<ObjectPresenter>>,
|
ObjectPresenter: '' as Ref<Mixin<ObjectPresenter>>,
|
||||||
ObjectEditorHeader: '' as Ref<Mixin<ObjectEditorHeader>>,
|
ObjectEditorHeader: '' as Ref<Mixin<ObjectEditorHeader>>,
|
||||||
ObjectEditorFooter: '' as Ref<Mixin<ObjectEditorFooter>>,
|
ObjectEditorFooter: '' as Ref<Mixin<ObjectEditorFooter>>,
|
||||||
|
ObjectPanelFooter: '' as Ref<Mixin<ObjectEditorFooter>>,
|
||||||
ObjectValidator: '' as Ref<Mixin<ObjectValidator>>,
|
ObjectValidator: '' as Ref<Mixin<ObjectValidator>>,
|
||||||
ObjectFactory: '' as Ref<Mixin<ObjectFactory>>,
|
ObjectFactory: '' as Ref<Mixin<ObjectFactory>>,
|
||||||
ObjectTitle: '' as Ref<Mixin<ObjectTitle>>,
|
ObjectTitle: '' as Ref<Mixin<ObjectTitle>>,
|
||||||
|
@ -236,6 +236,11 @@ export interface ObjectEditorFooter extends Class<Doc> {
|
|||||||
props?: Record<string, any>
|
props?: Record<string, any>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ObjectPanelFooter extends Class<Doc> {
|
||||||
|
editor: AnyComponent
|
||||||
|
props?: Record<string, any>
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
|
@ -13,29 +13,30 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
import contact, { Employee, Person, PersonAccount, formatName, getName } from '@hcengineering/contact'
|
import contact, { Employee, formatName, getName, Person, PersonAccount } from '@hcengineering/contact'
|
||||||
import core, {
|
import core, {
|
||||||
Account,
|
Account,
|
||||||
|
concatLink,
|
||||||
|
Doc,
|
||||||
Ref,
|
Ref,
|
||||||
Tx,
|
Tx,
|
||||||
TxCUD,
|
|
||||||
TxCreateDoc,
|
TxCreateDoc,
|
||||||
|
TxCUD,
|
||||||
TxMixin,
|
TxMixin,
|
||||||
TxProcessor,
|
TxProcessor,
|
||||||
TxUpdateDoc,
|
TxUpdateDoc,
|
||||||
UserStatus,
|
UserStatus
|
||||||
Doc,
|
|
||||||
concatLink
|
|
||||||
} from '@hcengineering/core'
|
} from '@hcengineering/core'
|
||||||
import love, {
|
import love, {
|
||||||
Invite,
|
Invite,
|
||||||
|
isOffice,
|
||||||
JoinRequest,
|
JoinRequest,
|
||||||
|
loveId,
|
||||||
MeetingMinutes,
|
MeetingMinutes,
|
||||||
|
MeetingStatus,
|
||||||
ParticipantInfo,
|
ParticipantInfo,
|
||||||
RequestStatus,
|
RequestStatus,
|
||||||
RoomAccess,
|
RoomAccess
|
||||||
isOffice,
|
|
||||||
loveId
|
|
||||||
} from '@hcengineering/love'
|
} from '@hcengineering/love'
|
||||||
import notification from '@hcengineering/notification'
|
import notification from '@hcengineering/notification'
|
||||||
import { getMetadata, translate } from '@hcengineering/platform'
|
import { getMetadata, translate } from '@hcengineering/platform'
|
||||||
@ -240,6 +241,40 @@ async function setDefaultRoomAccess (info: ParticipantInfo, control: TriggerCont
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function finishMeetingMinutes (
|
||||||
|
info: ParticipantInfo,
|
||||||
|
control: TriggerControl,
|
||||||
|
tx: TxCUD<ParticipantInfo>
|
||||||
|
): Promise<Tx[]> {
|
||||||
|
const res: Tx[] = []
|
||||||
|
const roomInfos = await control.queryFind(control.ctx, love.class.RoomInfo, {})
|
||||||
|
const roomInfo = roomInfos.find((ri) => ri.persons.includes(info.person))
|
||||||
|
|
||||||
|
if (roomInfo === undefined) {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentPersons = roomInfo.persons.filter((p) => p !== info.person)
|
||||||
|
|
||||||
|
if (currentPersons.length === 0) {
|
||||||
|
const meetingMinutes = await control.findAll(control.ctx, love.class.MeetingMinutes, {
|
||||||
|
attachedTo: roomInfo.room,
|
||||||
|
status: MeetingStatus.Active
|
||||||
|
})
|
||||||
|
|
||||||
|
for (const meeting of meetingMinutes) {
|
||||||
|
res.push(
|
||||||
|
control.txFactory.createTxUpdateDoc(meeting._class, meeting.space, meeting._id, {
|
||||||
|
status: MeetingStatus.Finished,
|
||||||
|
meetingEnd: tx.modifiedOn
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
export async function OnParticipantInfo (txes: Tx[], control: TriggerControl): Promise<Tx[]> {
|
export async function OnParticipantInfo (txes: Tx[], control: TriggerControl): Promise<Tx[]> {
|
||||||
const result: Tx[] = []
|
const result: Tx[] = []
|
||||||
for (const tx of txes) {
|
for (const tx of txes) {
|
||||||
@ -254,6 +289,7 @@ export async function OnParticipantInfo (txes: Tx[], control: TriggerControl): P
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
result.push(...(await setDefaultRoomAccess(removedInfo, control)))
|
result.push(...(await setDefaultRoomAccess(removedInfo, control)))
|
||||||
|
result.push(...(await finishMeetingMinutes(removedInfo, control, actualTx)))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (actualTx._class === core.class.TxUpdateDoc) {
|
if (actualTx._class === core.class.TxUpdateDoc) {
|
||||||
@ -269,6 +305,7 @@ export async function OnParticipantInfo (txes: Tx[], control: TriggerControl): P
|
|||||||
}
|
}
|
||||||
result.push(...(await rejectJoinRequests(info, control)))
|
result.push(...(await rejectJoinRequests(info, control)))
|
||||||
result.push(...(await setDefaultRoomAccess(info, control)))
|
result.push(...(await setDefaultRoomAccess(info, control)))
|
||||||
|
result.push(...(await finishMeetingMinutes(info, control, actualTx)))
|
||||||
result.push(...(await roomJoinHandler(info, control)))
|
result.push(...(await roomJoinHandler(info, control)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -949,7 +949,7 @@ export function createModel (builder: Builder): void {
|
|||||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||||
ofClass: github.class.GithubPullRequest,
|
ofClass: github.class.GithubPullRequest,
|
||||||
components: {
|
components: {
|
||||||
input: chunter.component.ChatMessageInput
|
input: { component: chunter.component.ChatMessageInput }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user