mirror of
https://github.com/hcengineering/platform.git
synced 2025-05-19 13:57:50 +00:00
Add meeting minutes status, fix messages collection
Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com>
This commit is contained in:
parent
6a21296d2b
commit
8cac2f9142
@ -201,11 +201,8 @@ export class TDocUpdateMessageViewlet extends TDoc implements DocUpdateMessageVi
|
||||
|
||||
@Model(activity.class.ActivityExtension, core.class.Doc, DOMAIN_MODEL)
|
||||
export class TActivityExtension extends TDoc implements ActivityExtension {
|
||||
@Prop(TypeRef(core.class.Class), core.string.Class)
|
||||
@Index(IndexKind.Indexed)
|
||||
ofClass!: Ref<Class<Doc>>
|
||||
|
||||
components!: Record<ActivityExtensionKind, AnyComponent>
|
||||
ofClass!: Ref<Class<Doc>>
|
||||
components!: Record<ActivityExtensionKind, { component: AnyComponent, props?: Record<string, any> }>
|
||||
}
|
||||
|
||||
@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, {
|
||||
ofClass: analyticsCollector.class.OnboardingChannel,
|
||||
components: { input: chunter.component.ChatMessageInput }
|
||||
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||
})
|
||||
|
||||
builder.createDoc<ActivityMessageControl<OnboardingChannel>>(
|
||||
|
@ -273,27 +273,27 @@ export function createModel (builder: Builder): void {
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
ofClass: chunter.class.Channel,
|
||||
components: { input: chunter.component.ChatMessageInput }
|
||||
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||
})
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
ofClass: chunter.class.DirectMessage,
|
||||
components: { input: chunter.component.ChatMessageInput }
|
||||
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||
})
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
ofClass: activity.class.DocUpdateMessage,
|
||||
components: { input: chunter.component.ChatMessageInput }
|
||||
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||
})
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
ofClass: chunter.class.ChatMessage,
|
||||
components: { input: chunter.component.ChatMessageInput }
|
||||
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||
})
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
ofClass: activity.class.ActivityReference,
|
||||
components: { input: chunter.component.ChatMessageInput }
|
||||
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||
})
|
||||
|
||||
// Indexing
|
||||
|
@ -263,22 +263,22 @@ export function createModel (builder: Builder): void {
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
ofClass: contact.class.Contact,
|
||||
components: { input: chunter.component.ChatMessageInput }
|
||||
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||
})
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
ofClass: contact.class.Person,
|
||||
components: { input: chunter.component.ChatMessageInput }
|
||||
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||
})
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
ofClass: contact.class.Organization,
|
||||
components: { input: chunter.component.ChatMessageInput }
|
||||
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||
})
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
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, {
|
||||
|
@ -514,7 +514,7 @@ export function createModel (builder: Builder): void {
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
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, {
|
||||
@ -768,7 +768,7 @@ export function defineNotifications (builder: Builder): void {
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
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, {
|
||||
|
@ -492,7 +492,7 @@ function defineDocument (builder: Builder): void {
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
ofClass: document.class.Document,
|
||||
components: { input: chunter.component.ChatMessageInput }
|
||||
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||
})
|
||||
|
||||
// Search
|
||||
|
@ -595,7 +595,7 @@ function defineFile (builder: Builder): void {
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
ofClass: drive.class.File,
|
||||
components: { input: chunter.component.ChatMessageInput }
|
||||
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||
})
|
||||
|
||||
// Search
|
||||
|
@ -85,17 +85,17 @@ export function createModel (builder: Builder): void {
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
ofClass: inventory.class.Product,
|
||||
components: { input: chunter.component.ChatMessageInput }
|
||||
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||
})
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
ofClass: inventory.class.Category,
|
||||
components: { input: chunter.component.ChatMessageInput }
|
||||
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||
})
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
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, {
|
||||
|
@ -51,12 +51,12 @@ export function createModel (builder: Builder): void {
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
ofClass: lead.class.Lead,
|
||||
components: { input: chunter.component.ChatMessageInput }
|
||||
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||
})
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
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, {
|
||||
|
@ -21,7 +21,8 @@ import {
|
||||
IndexKind,
|
||||
type Ref,
|
||||
type CollaborativeDoc,
|
||||
Doc
|
||||
type Doc,
|
||||
type Timestamp
|
||||
} from '@hcengineering/core'
|
||||
import {
|
||||
type DevicesPreference,
|
||||
@ -38,7 +39,8 @@ import {
|
||||
type RoomInfo,
|
||||
type RoomType,
|
||||
type RoomLanguage,
|
||||
type MeetingMinutes
|
||||
type MeetingMinutes,
|
||||
type MeetingStatus
|
||||
} from '@hcengineering/love'
|
||||
import {
|
||||
type Builder,
|
||||
@ -53,7 +55,9 @@ import {
|
||||
TypeCollaborativeDoc,
|
||||
TypeRef,
|
||||
TypeString,
|
||||
UX
|
||||
TypeTimestamp,
|
||||
UX,
|
||||
TypeAny
|
||||
} from '@hcengineering/model'
|
||||
import calendar, { TEvent } from '@hcengineering/model-calendar'
|
||||
import core, { TAttachedDoc, TDoc } from '@hcengineering/model-core'
|
||||
@ -108,6 +112,9 @@ export class TRoom extends TDoc implements Room {
|
||||
|
||||
@Prop(PropCollection(love.class.MeetingMinutes), love.string.MeetingMinutes)
|
||||
meetings?: number
|
||||
|
||||
@Prop(PropCollection(chunter.class.ChatMessage), activity.string.Messages)
|
||||
messages?: number
|
||||
}
|
||||
|
||||
@Model(love.class.Office, love.class.Room)
|
||||
@ -187,7 +194,7 @@ export class TMeeting extends TEvent implements Meeting {
|
||||
@Model(love.class.MeetingMinutes, core.class.Doc, DOMAIN_MEETING_MINUTES)
|
||||
@UX(love.string.MeetingMinutes, love.icon.Cam, undefined, undefined, love.string.MeetingsMinutes)
|
||||
export class TMeetingMinutes extends TAttachedDoc implements MeetingMinutes {
|
||||
@Prop(TypeRef(core.class.Doc), love.string.Room, {editor: love.component.MeetingMinutesDocEditor })
|
||||
@Prop(TypeRef(core.class.Doc), love.string.Room, { editor: love.component.MeetingMinutesDocEditor })
|
||||
@Index(IndexKind.Indexed)
|
||||
@ReadOnly()
|
||||
declare attachedTo: Ref<Doc>
|
||||
@ -203,6 +210,12 @@ export class TMeetingMinutes extends TAttachedDoc implements MeetingMinutes {
|
||||
@Index(IndexKind.FullText)
|
||||
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 })
|
||||
attachments?: number
|
||||
|
||||
@ -211,6 +224,15 @@ export class TMeetingMinutes extends TAttachedDoc implements MeetingMinutes {
|
||||
|
||||
@Prop(PropCollection(chunter.class.ChatMessage), activity.string.Messages)
|
||||
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
|
||||
}
|
||||
|
||||
export default love
|
||||
@ -424,17 +446,17 @@ export function createModel (builder: Builder): void {
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
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, {
|
||||
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, {
|
||||
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, {})
|
||||
@ -477,10 +499,11 @@ export function createModel (builder: Builder): void {
|
||||
descriptor: view.viewlet.Table,
|
||||
config: [
|
||||
'',
|
||||
{ key: 'status', presenter: love.component.MeetingMinutesStatusPresenter, label: love.string.Status },
|
||||
'createdOn',
|
||||
'meetingEnd',
|
||||
{ key: 'messages', displayProps: { key: 'messages', suffix: true } },
|
||||
{ key: 'transcription', displayProps: { key: 'transcription', suffix: true } },
|
||||
'modifiedOn',
|
||||
'modifiedBy'
|
||||
{ key: 'transcription', displayProps: { key: 'transcription', suffix: true } }
|
||||
],
|
||||
configOptions: {
|
||||
hiddenKeys: ['description'],
|
||||
|
@ -16,7 +16,16 @@
|
||||
import contact from '@hcengineering/contact'
|
||||
import { type Space, TxOperations, type Ref, makeCollaborativeDoc } from '@hcengineering/core'
|
||||
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 {
|
||||
createDefaultSpace,
|
||||
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, {
|
||||
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, {
|
||||
@ -299,7 +299,7 @@ function defineProductVersion (builder: Builder): void {
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
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, {
|
||||
|
@ -56,17 +56,17 @@ export function createModel (builder: Builder): void {
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
ofClass: recruit.class.Vacancy,
|
||||
components: { input: chunter.component.ChatMessageInput }
|
||||
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||
})
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
ofClass: recruit.class.Applicant,
|
||||
components: { input: chunter.component.ChatMessageInput }
|
||||
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||
})
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
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, {
|
||||
|
@ -91,7 +91,7 @@ export function createModel (builder: Builder): void {
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
ofClass: survey.class.Survey,
|
||||
components: { input: chunter.component.ChatMessageInput }
|
||||
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||
})
|
||||
|
||||
builder.createDoc<Viewlet>(
|
||||
|
@ -143,7 +143,7 @@ export function createModel (builder: Builder): void {
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
ofClass: testManagement.class.TestProject,
|
||||
components: { input: chunter.component.ChatMessageInput }
|
||||
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||
})
|
||||
|
||||
defineTestSuite(builder)
|
||||
@ -218,7 +218,7 @@ function defineTestSuite (builder: Builder): void {
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
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, {
|
||||
@ -283,7 +283,7 @@ function defineTestCase (builder: Builder): void {
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
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, {
|
||||
@ -388,7 +388,7 @@ function defineTestRun (builder: Builder): void {
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
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, {
|
||||
|
@ -461,22 +461,22 @@ export function createModel (builder: Builder): void {
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
ofClass: tracker.class.Issue,
|
||||
components: { input: chunter.component.ChatMessageInput }
|
||||
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||
})
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
ofClass: tracker.class.Milestone,
|
||||
components: { input: chunter.component.ChatMessageInput }
|
||||
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||
})
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
ofClass: tracker.class.Component,
|
||||
components: { input: chunter.component.ChatMessageInput }
|
||||
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||
})
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
ofClass: tracker.class.IssueTemplate,
|
||||
components: { input: chunter.component.ChatMessageInput }
|
||||
components: { input: { component: chunter.component.ChatMessageInput } }
|
||||
})
|
||||
|
||||
defineViewlets(builder)
|
||||
|
@ -24,5 +24,11 @@
|
||||
</script>
|
||||
|
||||
{#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}
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
$: attrViewletConfig = viewlet?.config?.[attributeModel.key]
|
||||
$: 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)
|
||||
|
||||
@ -42,7 +42,7 @@
|
||||
</script>
|
||||
|
||||
{#if isUnset}
|
||||
<div class="row overflow-label">
|
||||
<div class="unset row overflow-label">
|
||||
<span class="mr-1"><Icon icon={attributeIcon} size="small" /></span>
|
||||
<Label label={activity.string.Unset} />
|
||||
<span class="lower"><Label label={attributeModel.label} /></span>
|
||||
@ -89,6 +89,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
color: var(--global-primary-TextColor);
|
||||
}
|
||||
|
||||
.showMore {
|
||||
|
@ -210,7 +210,7 @@ export type ActivityExtensionKind = 'input'
|
||||
*/
|
||||
export interface ActivityExtension extends Doc {
|
||||
ofClass: Ref<Class<Doc>>
|
||||
components: Record<ActivityExtensionKind, AnyComponent>
|
||||
components: Record<ActivityExtensionKind, { component: AnyComponent, props?: Record<string, any> }>
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,6 +72,9 @@
|
||||
"StartMeeting": "Start meeting",
|
||||
"Video": "Video",
|
||||
"NoMeetingMinutes": "No meeting minutes",
|
||||
"JoinMeeting": "Join meeting"
|
||||
"JoinMeeting": "Join meeting",
|
||||
"MeetingStart": "Meeting start",
|
||||
"MeetingEnd": "Meeting end",
|
||||
"Status": "Status"
|
||||
}
|
||||
}
|
||||
|
@ -72,6 +72,9 @@
|
||||
"StartMeeting": "Iniciar reunión",
|
||||
"Video": "Video",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
|
@ -72,6 +72,9 @@
|
||||
"StartMeeting": "Démarrer la réunion",
|
||||
"Video": "Vidéo",
|
||||
"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"
|
||||
}
|
||||
}
|
@ -72,6 +72,9 @@
|
||||
"StartMeeting": "Inizia riunione",
|
||||
"Video": "Video",
|
||||
"NoMeetingMinutes": "Nessun verbale della riunione",
|
||||
"JoinMeeting": "Unisciti alla riunione"
|
||||
"JoinMeeting": "Unisciti alla riunione",
|
||||
"MeetingStart": "Inizio riunione",
|
||||
"MeetingEnd": "Fine riunione",
|
||||
"Status": "Stato"
|
||||
}
|
||||
}
|
||||
|
@ -72,6 +72,9 @@
|
||||
"StartMeeting": "Iniciar reunião",
|
||||
"Video": "Vídeo",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
|
@ -72,6 +72,9 @@
|
||||
"StartMeeting": "Начать встречу",
|
||||
"Video": "Видео",
|
||||
"NoMeetingMinutes": "Нет результатов встреч",
|
||||
"JoinMeeting": "Присоединиться к встрече"
|
||||
"JoinMeeting": "Присоединиться к встрече",
|
||||
"MeetingStart": "Начало встречи",
|
||||
"MeetingEnd": "Конец встречи",
|
||||
"Status": "Статус"
|
||||
}
|
||||
}
|
||||
|
@ -72,6 +72,9 @@
|
||||
"StartMeeting": "开始会议",
|
||||
"Video": "视频",
|
||||
"NoMeetingMinutes": "无会议记录",
|
||||
"JoinMeeting": "加入会议"
|
||||
"JoinMeeting": "加入会议",
|
||||
"MeetingStart": "会议开始",
|
||||
"MeetingEnd": "会议结束",
|
||||
"Status": "状态"
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,8 @@
|
||||
type CompAndProps,
|
||||
IconMoreV,
|
||||
ButtonMenu,
|
||||
DropdownIntlItem, IconMaximize
|
||||
DropdownIntlItem,
|
||||
IconMaximize
|
||||
} from '@hcengineering/ui'
|
||||
import view, { Action } from '@hcengineering/view'
|
||||
import { getActions } from '@hcengineering/view-resources'
|
||||
@ -268,9 +269,9 @@
|
||||
direction: 'top'
|
||||
}}
|
||||
kind={'secondary'}
|
||||
iconSize='medium'
|
||||
iconSize="medium"
|
||||
size={'large'}
|
||||
on:click={ maximize}
|
||||
on:click={maximize}
|
||||
/>
|
||||
{/if}
|
||||
{#if $isConnected && moreItems.length > 0}
|
||||
|
@ -19,11 +19,10 @@
|
||||
import { createEventDispatcher, onMount } from 'svelte'
|
||||
import { personByIdStore } from '@hcengineering/contact-resources'
|
||||
import { IntlString } from '@hcengineering/platform'
|
||||
import { openDoc } from '@hcengineering/view-resources'
|
||||
|
||||
import love from '../plugin'
|
||||
import { getRoomName, tryConnect } from '../utils'
|
||||
import { infos, invites, myInfo, myRequests, selectedRoomPlace, meetingMinutesStore } from '../stores'
|
||||
import { infos, invites, myInfo, myRequests, selectedRoomPlace, myOffice, currentRoom } from '../stores'
|
||||
|
||||
export let object: Room
|
||||
export let readonly: boolean = false
|
||||
@ -60,12 +59,6 @@
|
||||
)
|
||||
connecting = false
|
||||
selectedRoomPlace.set(undefined)
|
||||
|
||||
const meeting = $meetingMinutesStore
|
||||
|
||||
if (meeting !== undefined) {
|
||||
await openDoc(client.getHierarchy(), meeting)
|
||||
}
|
||||
}
|
||||
|
||||
let connectLabel: IntlString = love.string.StartMeeting
|
||||
@ -88,9 +81,9 @@
|
||||
focusIndex={1}
|
||||
/>
|
||||
</div>
|
||||
{#if (object._id !== $myInfo?.room && $myInfo !== undefined)}
|
||||
<ModernButton label={connectLabel} size="large" kind={'primary'} on:click={connect} loading={connecting} />
|
||||
{/if}
|
||||
{#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>
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { deviceOptionsStore as deviceInfo } from '@hcengineering/ui'
|
||||
import { deviceOptionsStore as deviceInfo } from '@hcengineering/ui'
|
||||
import { onDestroy, onMount } from 'svelte'
|
||||
import presentation from '@hcengineering/presentation'
|
||||
import { personByIdStore } from '@hcengineering/contact-resources'
|
||||
@ -47,8 +47,8 @@
|
||||
|
||||
if (
|
||||
!$isConnected &&
|
||||
!$isCurrentInstanceConnected &&
|
||||
$myInfo?.sessionId === getMetadata(presentation.metadata.SessionId)
|
||||
!$isCurrentInstanceConnected &&
|
||||
$myInfo?.sessionId === getMetadata(presentation.metadata.SessionId)
|
||||
) {
|
||||
const info = $infos.filter((p) => p.room === room._id)
|
||||
await tryConnect($personByIdStore, $myInfo, room, info, $myRequests, $invites)
|
||||
@ -57,5 +57,5 @@
|
||||
</script>
|
||||
|
||||
<div class="hulyPanels-container">
|
||||
<Hall />
|
||||
<Hall />
|
||||
</div>
|
||||
|
@ -17,7 +17,14 @@
|
||||
import { ObjectPresenter } from '@hcengineering/view-resources'
|
||||
|
||||
export let object: MeetingMinutes
|
||||
|
||||
</script>
|
||||
|
||||
<ObjectPresenter objectId={object.attachedTo} _class={object.attachedToClass} shouldShowAvatar={false} disabled props={{ type: 'text' }}/>
|
||||
<span class="label flex-row-center ml-3 no-word-wrap">
|
||||
<ObjectPresenter
|
||||
objectId={object.attachedTo}
|
||||
_class={object.attachedToClass}
|
||||
shouldShowAvatar={false}
|
||||
disabled
|
||||
props={{ type: 'text' }}
|
||||
/>
|
||||
</span>
|
||||
|
@ -15,22 +15,50 @@
|
||||
<script lang="ts">
|
||||
import type { Class, Doc, Ref, Space } from '@hcengineering/core'
|
||||
import { Label, Section } from '@hcengineering/ui'
|
||||
import { Table } from '@hcengineering/view-resources'
|
||||
import love from '@hcengineering/love'
|
||||
import { Table, ViewletsSettingButton } from '@hcengineering/view-resources'
|
||||
import { Viewlet, ViewletPreference } from '@hcengineering/view'
|
||||
|
||||
import love from '../plugin'
|
||||
|
||||
export let objectId: Ref<Doc>
|
||||
export let space: Ref<Space>
|
||||
export let _class: Ref<Class<Doc>>
|
||||
export let readonly: boolean = false
|
||||
export let meetings: number
|
||||
|
||||
let viewlet: Viewlet | undefined
|
||||
let preference: ViewletPreference | undefined
|
||||
let loading = true
|
||||
</script>
|
||||
|
||||
<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.TableMeetingMinutes }}
|
||||
kind={'tertiary'}
|
||||
bind:viewlet
|
||||
bind:loading
|
||||
bind:preference
|
||||
/>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="content">
|
||||
{#if meetings > 0}
|
||||
<Table
|
||||
_class={love.class.MeetingMinutes}
|
||||
config={['', 'transcription', 'messages']}
|
||||
config={preference?.config ?? [
|
||||
'',
|
||||
{
|
||||
key: 'status',
|
||||
label: love.string.Status,
|
||||
presenter: love.component.MeetingMinutesStatusPresenter
|
||||
},
|
||||
'messages',
|
||||
'createdOn',
|
||||
'meetingEnd'
|
||||
]}
|
||||
query={{ attachedTo: objectId }}
|
||||
loadingProps={{ length: meetings }}
|
||||
{readonly}
|
||||
|
@ -0,0 +1,45 @@
|
||||
<!--
|
||||
// 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 { getEmbeddedLabel } from '@hcengineering/platform'
|
||||
|
||||
export let object: MeetingMinutes | undefined
|
||||
export let value: MeetingStatus | undefined
|
||||
export let attributeKey: string | undefined
|
||||
|
||||
const displayData = {
|
||||
[MeetingStatus.Active]: {
|
||||
label: getEmbeddedLabel('Active'),
|
||||
type: StateType.Positive
|
||||
},
|
||||
[MeetingStatus.Finished]: {
|
||||
label: getEmbeddedLabel('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}
|
@ -27,10 +27,10 @@
|
||||
|
||||
return $isConnected
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
|
||||
{#if $currentRoom && showControlBar($currentRoom, $location, $myOffice)}
|
||||
<div class="flex-grow flex-shrink" >
|
||||
<ControlBar room={$currentRoom} />
|
||||
<div class="flex-grow flex-shrink">
|
||||
<ControlBar room={$currentRoom} />
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -15,7 +15,7 @@
|
||||
<script lang="ts">
|
||||
import { Person, PersonAccount } from '@hcengineering/contact'
|
||||
import { personByIdStore, UserInfo } from '@hcengineering/contact-resources'
|
||||
import { IdMap, getCurrentAccount } from '@hcengineering/core'
|
||||
import { IdMap, getCurrentAccount, Ref, Class, Doc } from '@hcengineering/core'
|
||||
import ui, {
|
||||
ModernButton,
|
||||
SplitButton,
|
||||
@ -40,8 +40,10 @@
|
||||
roomAccessLabel
|
||||
} from '@hcengineering/love'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { getObjectLinkFragment } from '@hcengineering/view-resources'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import love from '../plugin'
|
||||
import { currentRoom, infos, invites, myInfo, myOffice, myRequests } from '../stores'
|
||||
import { currentRoom, infos, invites, myInfo, myOffice, myRequests, meetingMinutesStore } from '../stores'
|
||||
import {
|
||||
getRoomName,
|
||||
isCameraEnabled,
|
||||
@ -58,9 +60,11 @@
|
||||
import CamSettingPopup from './CamSettingPopup.svelte'
|
||||
import MicSettingPopup from './MicSettingPopup.svelte'
|
||||
import RoomAccessPopup from './RoomAccessPopup.svelte'
|
||||
import view from '@hcengineering/view'
|
||||
|
||||
export let room: Room
|
||||
|
||||
const client = getClient()
|
||||
function getPerson (info: ParticipantInfo | undefined, employees: IdMap<Person>): Person | undefined {
|
||||
if (info !== undefined) {
|
||||
return employees.get(info.person)
|
||||
@ -104,12 +108,20 @@
|
||||
dispatch('close')
|
||||
}
|
||||
|
||||
function back (): void {
|
||||
closePanel()
|
||||
const loc = getCurrentLocation()
|
||||
loc.path[2] = loveId
|
||||
loc.path.length = 3
|
||||
navigate(loc)
|
||||
async function back (): Promise<void> {
|
||||
const meetingMinutes = $meetingMinutesStore
|
||||
if (meetingMinutes !== undefined) {
|
||||
const hierarchy = client.getHierarchy()
|
||||
const panelComponent = hierarchy.classHierarchyMixin(
|
||||
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 {
|
||||
|
@ -60,7 +60,9 @@
|
||||
$: if (sid != null && room !== undefined) {
|
||||
meetingQuery.query(love.class.MeetingMinutes, { sid, attachedTo: room._id }, async (res) => {
|
||||
meetingMinutes = res[0]
|
||||
meetingMinutesStore.set(meetingMinutes)
|
||||
if (meetingMinutes) {
|
||||
meetingMinutesStore.set(meetingMinutes)
|
||||
}
|
||||
isMeetingMinutesLoaded = true
|
||||
})
|
||||
} else {
|
||||
|
@ -21,6 +21,7 @@ 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 {
|
||||
copyGuestLink,
|
||||
@ -55,7 +56,8 @@ export default async (): Promise<Resources> => ({
|
||||
MeetingMinutesTable,
|
||||
PanelControlBar,
|
||||
RoomPresenter,
|
||||
MeetingMinutesDocEditor
|
||||
MeetingMinutesDocEditor,
|
||||
MeetingMinutesStatusPresenter
|
||||
},
|
||||
function: {
|
||||
CreateMeeting: createMeeting,
|
||||
|
@ -33,7 +33,8 @@ export default mergeIds(loveId, love, {
|
||||
MeetingMinutesTable: '' as AnyComponent,
|
||||
FloorView: '' as AnyComponent,
|
||||
PanelControlBar: '' as AnyComponent,
|
||||
MeetingMinutesDocEditor: '' as AnyComponent
|
||||
MeetingMinutesDocEditor: '' as AnyComponent,
|
||||
MeetingMinutesStatusPresenter: '' as AnyComponent
|
||||
},
|
||||
function: {
|
||||
CreateMeeting: '' as Resource<DocCreateFunction>,
|
||||
|
@ -30,7 +30,8 @@ import {
|
||||
RoomType,
|
||||
TranscriptionStatus,
|
||||
type RoomMetadata,
|
||||
type MeetingMinutes
|
||||
type MeetingMinutes,
|
||||
MeetingStatus
|
||||
} from '@hcengineering/love'
|
||||
import { getEmbeddedLabel, getMetadata, getResource, type IntlString } from '@hcengineering/platform'
|
||||
import presentation, {
|
||||
@ -39,7 +40,14 @@ import presentation, {
|
||||
type DocCreatePhase,
|
||||
getClient
|
||||
} 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 { BackgroundBlur, type BackgroundOptions, type ProcessorWrapper } from '@livekit/track-processors'
|
||||
import {
|
||||
@ -70,10 +78,11 @@ import {
|
||||
import { type Widget, type WidgetTab } from '@hcengineering/workbench'
|
||||
import view from '@hcengineering/view'
|
||||
import chunter from '@hcengineering/chunter'
|
||||
import { openDoc } from '@hcengineering/view-resources'
|
||||
|
||||
import { sendMessage } from './broadcast'
|
||||
import love from './plugin'
|
||||
import { $myPreferences, meetingMinutesStore, currentRoom } from './stores'
|
||||
import { $myPreferences, currentRoom, meetingMinutesStore, selectedRoomPlace } from './stores'
|
||||
import RoomSettingsPopup from './components/RoomSettingsPopup.svelte'
|
||||
|
||||
export const selectedCamId = 'selectedDevice_cam'
|
||||
@ -444,7 +453,6 @@ export async function disconnect (): Promise<void> {
|
||||
isMicEnabled.set(false)
|
||||
isCameraEnabled.set(false)
|
||||
isSharingEnabled.set(false)
|
||||
meetingMinutesStore.set(undefined)
|
||||
sendMessage({ type: 'mic', value: false })
|
||||
sendMessage({ type: 'cam', value: false })
|
||||
sendMessage({ type: 'share', value: false })
|
||||
@ -463,6 +471,22 @@ export async function leaveRoom (ownInfo: ParticipantInfo | undefined, ownOffice
|
||||
}
|
||||
}
|
||||
await disconnect()
|
||||
closeMeetingMinutes()
|
||||
}
|
||||
|
||||
function closeMeetingMinutes (): void {
|
||||
const loc = getCurrentLocation()
|
||||
|
||||
if (loc.path[2] === loveId) {
|
||||
const meetingMinutes = get(meetingMinutesStore)
|
||||
const panel = get(panelstore).panel
|
||||
const { _id } = panel ?? {}
|
||||
|
||||
if (_id !== undefined && meetingMinutes !== undefined && _id === meetingMinutes._id) {
|
||||
closePanel()
|
||||
}
|
||||
}
|
||||
meetingMinutesStore.set(undefined)
|
||||
}
|
||||
|
||||
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 sid = await lk.getSid()
|
||||
|
||||
@ -601,7 +625,17 @@ async function createMeetingMinutes (room: Room): Promise<void> {
|
||||
const doc = await client.findOne(love.class.MeetingMinutes, { sid })
|
||||
|
||||
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 newDoc: MeetingMinutes = {
|
||||
_id,
|
||||
@ -611,24 +645,35 @@ async function createMeetingMinutes (room: Room): Promise<void> {
|
||||
attachedToClass: room._class,
|
||||
collection: 'meetings',
|
||||
space: core.space.Workspace,
|
||||
title: room.name + ' ' + dateStr,
|
||||
title: `${room.name} ${date}`,
|
||||
description: makeCollaborativeDoc(_id, 'description'),
|
||||
status: MeetingStatus.Active,
|
||||
modifiedBy: getCurrentAccount()._id,
|
||||
modifiedOn: Date.now()
|
||||
}
|
||||
|
||||
await client.addCollection(
|
||||
love.class.MeetingMinutes,
|
||||
core.space.Workspace,
|
||||
room._id,
|
||||
room._class,
|
||||
'meetings',
|
||||
{ sid, title: newDoc.title, description: newDoc.description },
|
||||
{ sid, title: newDoc.title, description: newDoc.description, status: newDoc.status },
|
||||
_id
|
||||
)
|
||||
meetingMinutesStore.set(newDoc)
|
||||
const loc = getCurrentLocation()
|
||||
if (loc.path[2] === loveId) {
|
||||
await openDoc(client.getHierarchy(), newDoc)
|
||||
}
|
||||
} else {
|
||||
meetingMinutesStore.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 moveToRoom(x, y, currentInfo, currentPerson, room, getMetadata(presentation.metadata.SessionId) ?? null)
|
||||
await connectLK(currentPerson, room)
|
||||
await createMeetingMinutes(room)
|
||||
selectedRoomPlace.set(undefined)
|
||||
await openMeetingMinutes(room)
|
||||
}
|
||||
|
||||
export const joinRequest: Ref<JoinRequest> | undefined = undefined
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Event } from '@hcengineering/calendar'
|
||||
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 { NotificationType } from '@hcengineering/notification'
|
||||
import { Asset, IntlString, Metadata, Plugin, plugin } from '@hcengineering/platform'
|
||||
@ -105,6 +105,7 @@ export interface Room extends Doc {
|
||||
description: CollaborativeDoc
|
||||
attachments?: number
|
||||
meetings?: number
|
||||
messages?: number
|
||||
}
|
||||
|
||||
export interface Office extends Room {
|
||||
@ -158,12 +159,22 @@ export interface DevicesPreference extends Preference {
|
||||
camEnabled: boolean
|
||||
}
|
||||
|
||||
export enum MeetingStatus {
|
||||
Active,
|
||||
Finished
|
||||
}
|
||||
|
||||
export interface MeetingMinutes extends AttachedDoc {
|
||||
sid: string
|
||||
|
||||
title: string
|
||||
description: CollaborativeDoc
|
||||
|
||||
status: MeetingStatus
|
||||
meetingEnd?: Timestamp
|
||||
|
||||
transcription?: number
|
||||
messages?: number
|
||||
description: CollaborativeDoc
|
||||
attachments?: number
|
||||
}
|
||||
|
||||
@ -209,7 +220,10 @@ const love = plugin(loveId, {
|
||||
StartMeeting: '' as IntlString,
|
||||
Video: '' as IntlString,
|
||||
NoMeetingMinutes: '' as IntlString,
|
||||
JoinMeeting: '' as IntlString
|
||||
JoinMeeting: '' as IntlString,
|
||||
MeetingStart: '' as IntlString,
|
||||
MeetingEnd: '' as IntlString,
|
||||
Status: '' as IntlString
|
||||
},
|
||||
ids: {
|
||||
MainFloor: '' as Ref<Floor>,
|
||||
|
@ -359,8 +359,8 @@
|
||||
|
||||
<svelte:fragment slot="panel-footer">
|
||||
{#if panelFooter}
|
||||
<Component is={panelFooter.footer} props={{ object, _class, ...panelFooter.props, readonly }} />
|
||||
{/if}
|
||||
<Component is={panelFooter.footer} props={{ object, _class, ...panelFooter.props, readonly }} />
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</Panel>
|
||||
{/if}
|
||||
|
@ -27,7 +27,9 @@
|
||||
{#if kind === 'link'}
|
||||
<Button {kind} {size} {justify} {width}>
|
||||
<svelte:fragment slot="content">
|
||||
<TimeSince {value} />
|
||||
{#if value != null}
|
||||
<TimeSince {value} />
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</Button>
|
||||
{:else}
|
||||
|
@ -43,7 +43,6 @@ import {
|
||||
ListItemPresenter,
|
||||
ObjectEditor,
|
||||
ObjectEditorFooter,
|
||||
ObjectPanelFooter,
|
||||
ObjectEditorHeader,
|
||||
ObjectFactory,
|
||||
ObjectIcon,
|
||||
|
@ -13,29 +13,30 @@
|
||||
// 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, {
|
||||
Account,
|
||||
concatLink,
|
||||
Doc,
|
||||
Ref,
|
||||
Tx,
|
||||
TxCUD,
|
||||
TxCreateDoc,
|
||||
TxCUD,
|
||||
TxMixin,
|
||||
TxProcessor,
|
||||
TxUpdateDoc,
|
||||
UserStatus,
|
||||
Doc,
|
||||
concatLink
|
||||
UserStatus
|
||||
} from '@hcengineering/core'
|
||||
import love, {
|
||||
Invite,
|
||||
isOffice,
|
||||
JoinRequest,
|
||||
loveId,
|
||||
MeetingMinutes,
|
||||
MeetingStatus,
|
||||
ParticipantInfo,
|
||||
RequestStatus,
|
||||
RoomAccess,
|
||||
isOffice,
|
||||
loveId
|
||||
RoomAccess
|
||||
} from '@hcengineering/love'
|
||||
import notification from '@hcengineering/notification'
|
||||
import { getMetadata, translate } from '@hcengineering/platform'
|
||||
@ -240,6 +241,40 @@ async function setDefaultRoomAccess (info: ParticipantInfo, control: TriggerCont
|
||||
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[]> {
|
||||
const result: Tx[] = []
|
||||
for (const tx of txes) {
|
||||
@ -254,6 +289,7 @@ export async function OnParticipantInfo (txes: Tx[], control: TriggerControl): P
|
||||
continue
|
||||
}
|
||||
result.push(...(await setDefaultRoomAccess(removedInfo, control)))
|
||||
result.push(...(await finishMeetingMinutes(removedInfo, control, actualTx)))
|
||||
continue
|
||||
}
|
||||
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 setDefaultRoomAccess(info, control)))
|
||||
result.push(...(await finishMeetingMinutes(info, control, actualTx)))
|
||||
result.push(...(await roomJoinHandler(info, control)))
|
||||
}
|
||||
}
|
||||
|
@ -949,7 +949,7 @@ export function createModel (builder: Builder): void {
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
ofClass: github.class.GithubPullRequest,
|
||||
components: {
|
||||
input: chunter.component.ChatMessageInput
|
||||
input: { component: chunter.component.ChatMessageInput }
|
||||
}
|
||||
})
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user