mirror of
https://github.com/hcengineering/platform.git
synced 2024-11-22 03:14:40 +03:00
parent
820bbd1d17
commit
6967255648
@ -51,11 +51,11 @@ import { clearTelegramHistory } from './telegram'
|
||||
import { diffWorkspace, updateField } from './workspace'
|
||||
|
||||
import core, {
|
||||
AccountRole,
|
||||
getWorkspaceId,
|
||||
MeasureMetricsContext,
|
||||
metricsToString,
|
||||
versionToString,
|
||||
type AccountRole,
|
||||
type Data,
|
||||
type Tx,
|
||||
type Version
|
||||
@ -215,7 +215,7 @@ export function devTool (
|
||||
}
|
||||
console.log('assigning to workspace', workspaceInfo)
|
||||
try {
|
||||
await assignWorkspace(toolCtx, db, productId, email, workspaceInfo.workspace)
|
||||
await assignWorkspace(toolCtx, db, productId, email, workspaceInfo.workspace, AccountRole.User)
|
||||
} catch (err: any) {
|
||||
console.error(err)
|
||||
}
|
||||
|
@ -13,8 +13,8 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import core, { TxOperations } from '@hcengineering/core'
|
||||
import {
|
||||
createDefaultSpace,
|
||||
tryUpgrade,
|
||||
type MigrateOperation,
|
||||
type MigrationClient,
|
||||
@ -23,35 +23,14 @@ import {
|
||||
import bitrix from './plugin'
|
||||
import { bitrixId } from '@hcengineering/bitrix'
|
||||
|
||||
async function createSpace (tx: TxOperations): Promise<void> {
|
||||
const current = await tx.findOne(core.class.Space, {
|
||||
_id: bitrix.space.Mappings
|
||||
})
|
||||
if (current === undefined) {
|
||||
await tx.createDoc(
|
||||
core.class.Space,
|
||||
core.space.Space,
|
||||
{
|
||||
name: 'Bitrix mappings',
|
||||
description: 'Bitrix mappings',
|
||||
private: false,
|
||||
archived: false,
|
||||
members: []
|
||||
},
|
||||
bitrix.space.Mappings
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export const bitrixOperation: MigrateOperation = {
|
||||
async migrate (client: MigrationClient): Promise<void> {},
|
||||
async upgrade (client: MigrationUpgradeClient): Promise<void> {
|
||||
await tryUpgrade(client, bitrixId, [
|
||||
{
|
||||
state: 'create-defaults',
|
||||
state: 'create-defaults-v2',
|
||||
func: async (client) => {
|
||||
const tx = new TxOperations(client, core.account.System)
|
||||
await createSpace(tx)
|
||||
await createDefaultSpace(client, bitrix.space.Mappings, { name: 'Bitrix mappings' })
|
||||
}
|
||||
}
|
||||
])
|
||||
|
@ -38,7 +38,8 @@ import {
|
||||
type Ref,
|
||||
type Space,
|
||||
type Timestamp,
|
||||
IndexKind
|
||||
IndexKind,
|
||||
SortingOrder
|
||||
} from '@hcengineering/core'
|
||||
import {
|
||||
ArrOf,
|
||||
@ -205,7 +206,7 @@ const actionTemplates = template({
|
||||
}
|
||||
})
|
||||
|
||||
export function createModel (builder: Builder, options = { addApplication: true }): void {
|
||||
export function createModel (builder: Builder): void {
|
||||
builder.createModel(
|
||||
TChunterSpace,
|
||||
TChannel,
|
||||
@ -345,6 +346,25 @@ export function createModel (builder: Builder, options = { addApplication: true
|
||||
chunter.action.ArchiveChannel
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
view.class.Viewlet,
|
||||
core.space.Model,
|
||||
{
|
||||
attachTo: chunter.class.Channel,
|
||||
descriptor: view.viewlet.Table,
|
||||
viewOptions: {
|
||||
orderBy: [['modifiedOn', SortingOrder.Descending]],
|
||||
groupBy: [],
|
||||
other: []
|
||||
},
|
||||
configOptions: {
|
||||
strict: true
|
||||
},
|
||||
config: ['', 'topic', 'private', 'archived', 'members']
|
||||
},
|
||||
chunter.viewlet.Channels
|
||||
)
|
||||
|
||||
createAction(
|
||||
builder,
|
||||
{
|
||||
@ -382,21 +402,19 @@ export function createModel (builder: Builder, options = { addApplication: true
|
||||
chunter.action.ConvertToPrivate
|
||||
)
|
||||
|
||||
if (options.addApplication) {
|
||||
builder.createDoc(
|
||||
workbench.class.Application,
|
||||
core.space.Model,
|
||||
{
|
||||
label: chunter.string.ApplicationLabelChunter,
|
||||
icon: chunter.icon.Chunter,
|
||||
alias: chunterId,
|
||||
hidden: false,
|
||||
component: chunter.component.Chat,
|
||||
aside: chunter.component.ChatAside
|
||||
},
|
||||
chunter.app.Chunter
|
||||
)
|
||||
}
|
||||
builder.createDoc(
|
||||
workbench.class.Application,
|
||||
core.space.Model,
|
||||
{
|
||||
label: chunter.string.ApplicationLabelChunter,
|
||||
icon: chunter.icon.Chunter,
|
||||
alias: chunterId,
|
||||
hidden: false,
|
||||
component: chunter.component.Chat,
|
||||
aside: chunter.component.ChatAside
|
||||
},
|
||||
chunter.app.Chunter
|
||||
)
|
||||
|
||||
builder.mixin(activity.class.ActivityMessage, core.class.Class, view.mixin.LinkProvider, {
|
||||
encode: chunter.function.GetMessageLink
|
||||
|
@ -14,17 +14,26 @@
|
||||
//
|
||||
|
||||
import { chunterId } from '@hcengineering/chunter'
|
||||
import core, { type Class, type Doc, type Domain, type Ref, TxOperations } from '@hcengineering/core'
|
||||
import core, {
|
||||
type Account,
|
||||
TxOperations,
|
||||
type Class,
|
||||
type Doc,
|
||||
type Domain,
|
||||
type Ref,
|
||||
type Space
|
||||
} from '@hcengineering/core'
|
||||
import {
|
||||
tryMigrate,
|
||||
tryUpgrade,
|
||||
type MigrateOperation,
|
||||
type MigrationClient,
|
||||
type MigrationUpgradeClient,
|
||||
tryMigrate,
|
||||
tryUpgrade
|
||||
type MigrationUpgradeClient
|
||||
} from '@hcengineering/model'
|
||||
import activity, { DOMAIN_ACTIVITY } from '@hcengineering/model-activity'
|
||||
import notification from '@hcengineering/notification'
|
||||
|
||||
import contactPlugin, { type PersonAccount } from '@hcengineering/contact'
|
||||
import chunter from './plugin'
|
||||
|
||||
export const DOMAIN_COMMENT = 'comment' as Domain
|
||||
@ -59,48 +68,91 @@ export async function createDocNotifyContexts (
|
||||
}
|
||||
|
||||
export async function createGeneral (client: MigrationUpgradeClient, tx: TxOperations): Promise<void> {
|
||||
const createTx = await tx.findOne(core.class.TxCreateDoc, {
|
||||
objectId: chunter.space.General
|
||||
})
|
||||
const current = await tx.findOne(chunter.class.Channel, { _id: chunter.space.General })
|
||||
if (current !== undefined) {
|
||||
if (current.autoJoin === undefined) {
|
||||
await tx.update(current, {
|
||||
autoJoin: true
|
||||
})
|
||||
await joinEmployees(current, tx)
|
||||
}
|
||||
} else {
|
||||
const createTx = await tx.findOne(core.class.TxCreateDoc, {
|
||||
objectId: chunter.space.General
|
||||
})
|
||||
|
||||
if (createTx === undefined) {
|
||||
await tx.createDoc(
|
||||
chunter.class.Channel,
|
||||
core.space.Space,
|
||||
{
|
||||
name: 'general',
|
||||
description: 'General Channel',
|
||||
topic: 'General Channel',
|
||||
private: false,
|
||||
archived: false,
|
||||
members: []
|
||||
},
|
||||
chunter.space.General
|
||||
)
|
||||
if (createTx === undefined) {
|
||||
await tx.createDoc(
|
||||
chunter.class.Channel,
|
||||
core.space.Space,
|
||||
{
|
||||
name: 'general',
|
||||
description: 'General Channel',
|
||||
topic: 'General Channel',
|
||||
private: false,
|
||||
archived: false,
|
||||
members: await getAllEmployeeAccounts(tx),
|
||||
autoJoin: true
|
||||
},
|
||||
chunter.space.General
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
await createDocNotifyContexts(client, tx, chunter.space.General, chunter.class.Channel)
|
||||
}
|
||||
|
||||
export async function createRandom (client: MigrationUpgradeClient, tx: TxOperations): Promise<void> {
|
||||
const createTx = await tx.findOne(core.class.TxCreateDoc, {
|
||||
objectId: chunter.space.Random
|
||||
async function getAllEmployeeAccounts (tx: TxOperations): Promise<Ref<PersonAccount>[]> {
|
||||
const employees = await tx.findAll(contactPlugin.mixin.Employee, { active: true })
|
||||
const accounts = await tx.findAll(contactPlugin.class.PersonAccount, {
|
||||
person: { $in: employees.map((it) => it._id) }
|
||||
})
|
||||
return accounts.map((it) => it._id)
|
||||
}
|
||||
|
||||
if (createTx === undefined) {
|
||||
await tx.createDoc(
|
||||
chunter.class.Channel,
|
||||
core.space.Space,
|
||||
{
|
||||
name: 'random',
|
||||
description: 'Random Talks',
|
||||
topic: 'Random Talks',
|
||||
private: false,
|
||||
archived: false,
|
||||
members: []
|
||||
},
|
||||
chunter.space.Random
|
||||
)
|
||||
async function joinEmployees (current: Space, tx: TxOperations): Promise<void> {
|
||||
const accs = await getAllEmployeeAccounts(tx)
|
||||
const newMembers: Ref<Account>[] = [...current.members]
|
||||
for (const acc of accs) {
|
||||
if (!newMembers.includes(acc)) {
|
||||
newMembers.push(acc)
|
||||
}
|
||||
}
|
||||
await tx.update(current, {
|
||||
members: newMembers
|
||||
})
|
||||
}
|
||||
|
||||
export async function createRandom (client: MigrationUpgradeClient, tx: TxOperations): Promise<void> {
|
||||
const current = await tx.findOne(chunter.class.Channel, { _id: chunter.space.Random })
|
||||
if (current !== undefined) {
|
||||
if (current.autoJoin === undefined) {
|
||||
await tx.update(current, {
|
||||
autoJoin: true
|
||||
})
|
||||
await joinEmployees(current, tx)
|
||||
}
|
||||
} else {
|
||||
const createTx = await tx.findOne(core.class.TxCreateDoc, {
|
||||
objectId: chunter.space.Random
|
||||
})
|
||||
|
||||
if (createTx === undefined) {
|
||||
await tx.createDoc(
|
||||
chunter.class.Channel,
|
||||
core.space.Space,
|
||||
{
|
||||
name: 'random',
|
||||
description: 'Random Talks',
|
||||
topic: 'Random Talks',
|
||||
private: false,
|
||||
archived: false,
|
||||
members: await getAllEmployeeAccounts(tx),
|
||||
autoJoin: true
|
||||
},
|
||||
chunter.space.Random
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
await createDocNotifyContexts(client, tx, chunter.space.Random, chunter.class.Channel)
|
||||
@ -139,7 +191,7 @@ export const chunterOperation: MigrateOperation = {
|
||||
async upgrade (client: MigrationUpgradeClient): Promise<void> {
|
||||
await tryUpgrade(client, chunterId, [
|
||||
{
|
||||
state: 'create-defaults',
|
||||
state: 'create-defaults-v2',
|
||||
func: async (client) => {
|
||||
const tx = new TxOperations(client, core.account.System)
|
||||
await createGeneral(client, tx)
|
||||
|
@ -21,7 +21,7 @@ import { type NotificationGroup } from '@hcengineering/notification'
|
||||
import type { IntlString, Resource } from '@hcengineering/platform'
|
||||
import { mergeIds } from '@hcengineering/platform'
|
||||
import type { AnyComponent, Location } from '@hcengineering/ui/src/types'
|
||||
import type { Action, ActionCategory, ViewAction, ViewletDescriptor } from '@hcengineering/view'
|
||||
import type { Action, ActionCategory, ViewAction, Viewlet, ViewletDescriptor } from '@hcengineering/view'
|
||||
|
||||
export default mergeIds(chunterId, chunter, {
|
||||
component: {
|
||||
@ -76,7 +76,8 @@ export default mergeIds(chunterId, chunter, {
|
||||
RepliedToThread: '' as IntlString
|
||||
},
|
||||
viewlet: {
|
||||
Chat: '' as Ref<ViewletDescriptor>
|
||||
Chat: '' as Ref<ViewletDescriptor>,
|
||||
Channels: '' as Ref<Viewlet>
|
||||
},
|
||||
ids: {
|
||||
TxCommentCreate: '' as Ref<TxViewlet>,
|
||||
|
@ -27,21 +27,20 @@ import {
|
||||
type GetAvatarUrl,
|
||||
type Member,
|
||||
type Organization,
|
||||
type Organizations,
|
||||
type Person,
|
||||
type PersonAccount,
|
||||
type Persons,
|
||||
type Status
|
||||
} from '@hcengineering/contact'
|
||||
import {
|
||||
AccountRole,
|
||||
DOMAIN_MODEL,
|
||||
DateRangeMode,
|
||||
IndexKind,
|
||||
type Class,
|
||||
type Domain,
|
||||
type Markup,
|
||||
type Ref,
|
||||
type Timestamp,
|
||||
type Markup
|
||||
type Timestamp
|
||||
} from '@hcengineering/core'
|
||||
import {
|
||||
Collection,
|
||||
@ -53,17 +52,18 @@ import {
|
||||
ReadOnly,
|
||||
TypeAttachment,
|
||||
TypeBoolean,
|
||||
TypeCollaborativeMarkup,
|
||||
TypeDate,
|
||||
TypeRef,
|
||||
TypeString,
|
||||
TypeTimestamp,
|
||||
UX,
|
||||
type Builder,
|
||||
TypeCollaborativeMarkup
|
||||
type Builder
|
||||
} from '@hcengineering/model'
|
||||
import attachment from '@hcengineering/model-attachment'
|
||||
import chunter from '@hcengineering/model-chunter'
|
||||
import core, { TAccount, TAttachedDoc, TDoc, TSpace } from '@hcengineering/model-core'
|
||||
import core, { TAccount, TAttachedDoc, TDoc } from '@hcengineering/model-core'
|
||||
import { createPublicLinkAction } from '@hcengineering/model-guest'
|
||||
import { generateClassNotificationTypes } from '@hcengineering/model-notification'
|
||||
import presentation from '@hcengineering/model-presentation'
|
||||
import view, { createAction, type Viewlet } from '@hcengineering/model-view'
|
||||
@ -75,7 +75,6 @@ import templates from '@hcengineering/templates'
|
||||
import { type AnyComponent } from '@hcengineering/ui/src/types'
|
||||
import { type Action } from '@hcengineering/view'
|
||||
import contact from './plugin'
|
||||
import { createPublicLinkAction } from '@hcengineering/model-guest'
|
||||
|
||||
export { contactId } from '@hcengineering/contact'
|
||||
export { contactOperation } from './migration'
|
||||
@ -197,14 +196,6 @@ export class TPersonAccount extends TAccount implements PersonAccount {
|
||||
person!: Ref<Person>
|
||||
}
|
||||
|
||||
@Model(contact.class.Organizations, core.class.Space)
|
||||
@UX(contact.string.OrganizationsFolder, contact.icon.Company)
|
||||
export class TOrganizations extends TSpace implements Organizations {}
|
||||
|
||||
@Model(contact.class.Persons, core.class.Space)
|
||||
@UX(contact.string.PersonsFolder, contact.icon.Person)
|
||||
export class TPersons extends TSpace implements Persons {}
|
||||
|
||||
@Model(contact.class.ContactsTab, core.class.Doc, DOMAIN_MODEL)
|
||||
export class TContactsTab extends TDoc implements ContactsTab {
|
||||
label!: IntlString
|
||||
@ -218,9 +209,7 @@ export function createModel (builder: Builder): void {
|
||||
TChannelProvider,
|
||||
TContact,
|
||||
TPerson,
|
||||
TPersons,
|
||||
TOrganization,
|
||||
TOrganizations,
|
||||
TEmployee,
|
||||
TPersonAccount,
|
||||
TChannel,
|
||||
@ -311,6 +300,7 @@ export function createModel (builder: Builder): void {
|
||||
label: contact.string.Contacts,
|
||||
icon: contact.icon.ContactApplication,
|
||||
alias: contactId,
|
||||
accessLevel: AccountRole.User,
|
||||
hidden: false,
|
||||
// component: contact.component.ContactsTabs,
|
||||
locationResolver: contact.resolver.Location,
|
||||
@ -735,7 +725,8 @@ export function createModel (builder: Builder): void {
|
||||
presenter: contact.component.PersonAccountPresenter
|
||||
})
|
||||
builder.mixin(core.class.Account, core.class.Class, view.mixin.AttributePresenter, {
|
||||
presenter: contact.component.PersonAccountRefPresenter
|
||||
presenter: contact.component.PersonAccountRefPresenter,
|
||||
arrayPresenter: contact.component.AccountArrayEditor
|
||||
})
|
||||
|
||||
builder.mixin(contact.class.Organization, core.class.Class, view.mixin.ObjectPresenter, {
|
||||
|
@ -1,57 +1,21 @@
|
||||
//
|
||||
|
||||
import { type Class, DOMAIN_TX, type Doc, type Domain, type Ref, TxOperations } from '@hcengineering/core'
|
||||
import { DOMAIN_TX, type Space, TxOperations, type Class, type Doc, type Domain, type Ref } from '@hcengineering/core'
|
||||
import {
|
||||
createDefaultSpace,
|
||||
tryMigrate,
|
||||
tryUpgrade,
|
||||
type MigrateOperation,
|
||||
type MigrationClient,
|
||||
type MigrationUpgradeClient,
|
||||
type ModelLogger,
|
||||
tryMigrate,
|
||||
tryUpgrade
|
||||
type ModelLogger
|
||||
} from '@hcengineering/model'
|
||||
import activity, { DOMAIN_ACTIVITY } from '@hcengineering/model-activity'
|
||||
import core from '@hcengineering/model-core'
|
||||
import { DOMAIN_VIEW } from '@hcengineering/model-view'
|
||||
import activity, { DOMAIN_ACTIVITY } from '@hcengineering/model-activity'
|
||||
|
||||
import contact, { DOMAIN_CONTACT, contactId } from './index'
|
||||
|
||||
async function createSpace (tx: TxOperations): Promise<void> {
|
||||
const current = await tx.findOne(core.class.Space, {
|
||||
_id: contact.space.Employee
|
||||
})
|
||||
if (current === undefined) {
|
||||
await tx.createDoc(
|
||||
core.class.Space,
|
||||
core.space.Space,
|
||||
{
|
||||
name: 'Employees',
|
||||
description: 'Employees',
|
||||
private: false,
|
||||
archived: false,
|
||||
members: []
|
||||
},
|
||||
contact.space.Employee
|
||||
)
|
||||
}
|
||||
const contacts = await tx.findOne(core.class.Space, {
|
||||
_id: contact.space.Contacts
|
||||
})
|
||||
if (contacts === undefined) {
|
||||
await tx.createDoc(
|
||||
core.class.Space,
|
||||
core.space.Space,
|
||||
{
|
||||
name: 'Contacts',
|
||||
description: 'Contacts',
|
||||
private: false,
|
||||
archived: false,
|
||||
members: []
|
||||
},
|
||||
contact.space.Contacts
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async function createEmployeeEmail (client: TxOperations): Promise<void> {
|
||||
const employees = await client.findAll(contact.mixin.Employee, {})
|
||||
const channels = (
|
||||
@ -205,16 +169,29 @@ export const contactOperation: MigrateOperation = {
|
||||
}
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
state: 'removeEmployeeSpace',
|
||||
func: async (client) => {
|
||||
await client.update(
|
||||
DOMAIN_CONTACT,
|
||||
{
|
||||
space: 'contact:space:Employee' as Ref<Space>
|
||||
},
|
||||
{
|
||||
space: contact.space.Contacts
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
])
|
||||
},
|
||||
async upgrade (client: MigrationUpgradeClient): Promise<void> {
|
||||
await tryUpgrade(client, contactId, [
|
||||
{
|
||||
state: 'createSpace',
|
||||
state: 'createSpace-v2',
|
||||
func: async (client) => {
|
||||
const tx = new TxOperations(client, core.account.System)
|
||||
await createSpace(tx)
|
||||
await createDefaultSpace(client, contact.space.Contacts, { name: 'Contacts', description: 'Contacts' })
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -88,7 +88,8 @@ import {
|
||||
TSpace,
|
||||
TSpaceType,
|
||||
TSpaceTypeDescriptor,
|
||||
TTypedSpace
|
||||
TTypedSpace,
|
||||
TSystemSpace
|
||||
} from './security'
|
||||
import { TStatus, TStatusCategory, TDomainStatusPlaceholder } from './status'
|
||||
import { TUserStatus } from './transient'
|
||||
@ -131,6 +132,7 @@ export function createModel (builder: Builder): void {
|
||||
TTxApplyIf,
|
||||
TTxWorkspaceEvent,
|
||||
TSpace,
|
||||
TSystemSpace,
|
||||
TTypedSpace,
|
||||
TSpaceType,
|
||||
TSpaceTypeDescriptor,
|
||||
|
@ -14,23 +14,23 @@
|
||||
//
|
||||
|
||||
import core, {
|
||||
coreId,
|
||||
DOMAIN_DOC_INDEX_STATE,
|
||||
DOMAIN_STATUS,
|
||||
isClassIndexable,
|
||||
type Status,
|
||||
TxOperations,
|
||||
generateId,
|
||||
DOMAIN_TX,
|
||||
type TxCreateDoc,
|
||||
type Space
|
||||
coreId,
|
||||
generateId,
|
||||
isClassIndexable,
|
||||
type Space,
|
||||
type Status,
|
||||
type TxCreateDoc
|
||||
} from '@hcengineering/core'
|
||||
import {
|
||||
tryMigrate,
|
||||
tryUpgrade,
|
||||
type MigrateOperation,
|
||||
type MigrationClient,
|
||||
type MigrationUpgradeClient
|
||||
type MigrationUpgradeClient,
|
||||
createDefaultSpace,
|
||||
tryMigrate,
|
||||
tryUpgrade
|
||||
} from '@hcengineering/model'
|
||||
import { DOMAIN_SPACE } from './security'
|
||||
|
||||
@ -149,28 +149,14 @@ export const coreOperation: MigrateOperation = {
|
||||
async upgrade (client: MigrationUpgradeClient): Promise<void> {
|
||||
await tryUpgrade(client, coreId, [
|
||||
{
|
||||
state: 'create-defaults',
|
||||
state: 'create-defaults-v2',
|
||||
func: async (client) => {
|
||||
const tx = new TxOperations(client, core.account.System)
|
||||
|
||||
const spaceSpace = await tx.findOne(core.class.Space, {
|
||||
_id: core.space.Space
|
||||
})
|
||||
if (spaceSpace === undefined) {
|
||||
await tx.createDoc(
|
||||
core.class.TypedSpace,
|
||||
core.space.Space,
|
||||
{
|
||||
name: 'Space for all spaces',
|
||||
description: 'Spaces',
|
||||
private: false,
|
||||
archived: false,
|
||||
members: [],
|
||||
type: core.spaceType.SpacesType
|
||||
},
|
||||
core.space.Space
|
||||
)
|
||||
}
|
||||
await createDefaultSpace(
|
||||
client,
|
||||
core.space.Space,
|
||||
{ name: 'Spaces', description: 'Space for all spaces', type: core.spaceType.SpacesType },
|
||||
core.class.TypedSpace
|
||||
)
|
||||
}
|
||||
}
|
||||
])
|
||||
|
@ -70,13 +70,20 @@ export class TSpace extends TDoc implements Space {
|
||||
archived!: boolean
|
||||
|
||||
@Prop(ArrOf(TypeRef(core.class.Account)), core.string.Members)
|
||||
@Hidden()
|
||||
members!: Arr<Ref<Account>>
|
||||
|
||||
@Prop(ArrOf(TypeRef(core.class.Account)), core.string.Owners)
|
||||
owners?: Ref<Account>[]
|
||||
|
||||
@Prop(TypeBoolean(), getEmbeddedLabel('Auto-Join members'))
|
||||
@Hidden() // let's hide it for now
|
||||
autoJoin?: boolean
|
||||
}
|
||||
|
||||
@Model(core.class.SystemSpace, core.class.Space)
|
||||
@UX(core.string.Space, undefined, undefined, 'name')
|
||||
export class TSystemSpace extends TSpace implements Space {}
|
||||
|
||||
@Model(core.class.TypedSpace, core.class.Space)
|
||||
@UX(core.string.TypedSpace, undefined, undefined, 'name')
|
||||
export class TTypedSpace extends TSpace implements TypedSpace {
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
import activity from '@hcengineering/activity'
|
||||
import type { Class, CollaborativeDoc, CollectionSize, Domain, Role, RolesAssignment } from '@hcengineering/core'
|
||||
import { IndexKind, Account, Ref } from '@hcengineering/core'
|
||||
import { IndexKind, Account, Ref, AccountRole } from '@hcengineering/core'
|
||||
import {
|
||||
type Document,
|
||||
type DocumentEmbedding,
|
||||
@ -207,6 +207,20 @@ function defineTeamspace (builder: Builder): void {
|
||||
presenter: document.component.TeamspaceSpacePresenter
|
||||
})
|
||||
|
||||
builder.createDoc(
|
||||
view.class.Viewlet,
|
||||
core.space.Model,
|
||||
{
|
||||
attachTo: document.class.Teamspace,
|
||||
descriptor: view.viewlet.Table,
|
||||
configOptions: {
|
||||
hiddenKeys: ['name', 'description']
|
||||
},
|
||||
config: ['', 'members', 'private', 'archived']
|
||||
},
|
||||
document.viewlet.TeamspaceTable
|
||||
)
|
||||
|
||||
// Actions
|
||||
|
||||
builder.mixin(document.class.Teamspace, core.class.Class, view.mixin.IgnoreActions, {
|
||||
@ -451,7 +465,20 @@ function defineApplication (builder: Builder): void {
|
||||
hidden: false,
|
||||
locationResolver: document.resolver.Location,
|
||||
navigatorModel: {
|
||||
specials: [],
|
||||
specials: [
|
||||
{
|
||||
id: 'browser',
|
||||
accessLevel: AccountRole.User,
|
||||
label: document.string.Teamspaces,
|
||||
icon: view.icon.List,
|
||||
component: workbench.component.SpecialView,
|
||||
componentProps: {
|
||||
_class: document.class.Teamspace,
|
||||
label: document.string.Teamspaces
|
||||
},
|
||||
position: 'top'
|
||||
}
|
||||
],
|
||||
spaces: [
|
||||
{
|
||||
id: 'teamspaces',
|
||||
@ -459,7 +486,6 @@ function defineApplication (builder: Builder): void {
|
||||
spaceClass: document.class.Teamspace,
|
||||
addSpaceLabel: document.string.CreateTeamspace,
|
||||
createComponent: document.component.CreateTeamspace,
|
||||
visibleIf: document.function.IsTeamspaceVisible,
|
||||
icon: document.icon.Teamspace,
|
||||
// intentionally left empty in order to make space presenter working
|
||||
specials: []
|
||||
|
@ -14,14 +14,13 @@
|
||||
//
|
||||
|
||||
import { type Attachment } from '@hcengineering/attachment'
|
||||
import { type Class, type Doc, type Ref, TxOperations, DOMAIN_TX, getCollaborativeDoc } from '@hcengineering/core'
|
||||
import { DOMAIN_TX, getCollaborativeDoc, type Class, type Doc, type Ref } from '@hcengineering/core'
|
||||
import { type Document, type Teamspace } from '@hcengineering/document'
|
||||
import {
|
||||
tryMigrate,
|
||||
type MigrateOperation,
|
||||
type MigrationClient,
|
||||
type MigrationUpgradeClient,
|
||||
tryMigrate,
|
||||
tryUpgrade
|
||||
type MigrationUpgradeClient
|
||||
} from '@hcengineering/model'
|
||||
import { DOMAIN_ATTACHMENT } from '@hcengineering/model-attachment'
|
||||
import core, { DOMAIN_SPACE } from '@hcengineering/model-core'
|
||||
@ -29,26 +28,6 @@ import { type Asset } from '@hcengineering/platform'
|
||||
|
||||
import document, { documentId, DOMAIN_DOCUMENT } from './index'
|
||||
|
||||
async function createSpace (tx: TxOperations): Promise<void> {
|
||||
const documents = await tx.findOne(core.class.Space, {
|
||||
_id: document.space.Documents
|
||||
})
|
||||
if (documents === undefined) {
|
||||
await tx.createDoc(
|
||||
core.class.Space,
|
||||
core.space.Space,
|
||||
{
|
||||
name: 'Documents',
|
||||
description: 'Documents',
|
||||
private: false,
|
||||
archived: false,
|
||||
members: []
|
||||
},
|
||||
document.space.Documents
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async function migrateCollaborativeContent (client: MigrationClient): Promise<void> {
|
||||
const attachedFiles = await client.find<Attachment>(DOMAIN_ATTACHMENT, {
|
||||
_class: 'document:class:CollaboratorDocument' as Ref<Class<Doc>>,
|
||||
@ -330,15 +309,5 @@ export const documentOperation: MigrateOperation = {
|
||||
])
|
||||
},
|
||||
|
||||
async upgrade (client: MigrationUpgradeClient): Promise<void> {
|
||||
await tryUpgrade(client, documentId, [
|
||||
{
|
||||
state: 'u-default-project',
|
||||
func: async (client) => {
|
||||
const tx = new TxOperations(client, core.account.System)
|
||||
await createSpace(tx)
|
||||
}
|
||||
}
|
||||
])
|
||||
}
|
||||
async upgrade (client: MigrationUpgradeClient): Promise<void> {}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ import { type ObjectSearchCategory, type ObjectSearchFactory } from '@hcengineer
|
||||
import { type IntlString, mergeIds, type Resource } from '@hcengineering/platform'
|
||||
import { type TagCategory } from '@hcengineering/tags'
|
||||
import { type AnyComponent } from '@hcengineering/ui'
|
||||
import { type Action, type ActionCategory, type ViewAction } from '@hcengineering/view'
|
||||
import { type Viewlet, type Action, type ActionCategory, type ViewAction } from '@hcengineering/view'
|
||||
|
||||
export default mergeIds(documentId, document, {
|
||||
component: {
|
||||
@ -45,6 +45,9 @@ export default mergeIds(documentId, document, {
|
||||
action: {
|
||||
PublicLink: '' as Ref<Action<Doc, any>>
|
||||
},
|
||||
viewlet: {
|
||||
TeamspaceTable: '' as Ref<Viewlet>
|
||||
},
|
||||
category: {
|
||||
Document: '' as Ref<ActionCategory>,
|
||||
Other: '' as Ref<TagCategory>
|
||||
|
@ -13,41 +13,27 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import core, { TxOperations } from '@hcengineering/core'
|
||||
import { gmailId } from '@hcengineering/gmail'
|
||||
import {
|
||||
createDefaultSpace,
|
||||
tryUpgrade,
|
||||
type MigrateOperation,
|
||||
type MigrationClient,
|
||||
type MigrationUpgradeClient
|
||||
} from '@hcengineering/model'
|
||||
import gmail from './plugin'
|
||||
import { gmailId } from '@hcengineering/gmail'
|
||||
|
||||
export const gmailOperation: MigrateOperation = {
|
||||
async migrate (client: MigrationClient): Promise<void> {},
|
||||
async upgrade (client: MigrationUpgradeClient): Promise<void> {
|
||||
await tryUpgrade(client, gmailId, [
|
||||
{
|
||||
state: 'create-defaults',
|
||||
state: 'create-defaults-v2',
|
||||
func: async (client) => {
|
||||
const tx = new TxOperations(client, core.account.System)
|
||||
const current = await tx.findOne(core.class.Space, {
|
||||
_id: gmail.space.Gmail
|
||||
await createDefaultSpace(client, gmail.space.Gmail, {
|
||||
name: 'Gmail',
|
||||
description: 'Space for all gmail messages'
|
||||
})
|
||||
if (current === undefined) {
|
||||
await tx.createDoc(
|
||||
core.class.Space,
|
||||
core.space.Space,
|
||||
{
|
||||
name: 'Gmail',
|
||||
description: 'Space for all gmail messages',
|
||||
private: false,
|
||||
archived: false,
|
||||
members: []
|
||||
},
|
||||
gmail.space.Gmail
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
])
|
||||
|
@ -31,7 +31,7 @@ export function createModel (builder: Builder): void {
|
||||
core.space.Model,
|
||||
{
|
||||
email: guestAccountEmail,
|
||||
role: AccountRole.Guest
|
||||
role: AccountRole.DocGuest
|
||||
},
|
||||
guest.account.Guest
|
||||
)
|
||||
|
@ -1,48 +1,17 @@
|
||||
import {
|
||||
type Account,
|
||||
AccountRole,
|
||||
DOMAIN_TX,
|
||||
type TxCreateDoc,
|
||||
TxOperations,
|
||||
type TxUpdateDoc
|
||||
} from '@hcengineering/core'
|
||||
import { AccountRole, DOMAIN_TX, type Account, type TxCreateDoc, type TxUpdateDoc } from '@hcengineering/core'
|
||||
import { guestId } from '@hcengineering/guest'
|
||||
import {
|
||||
createDefaultSpace,
|
||||
tryMigrate,
|
||||
tryUpgrade,
|
||||
type MigrateOperation,
|
||||
type MigrationClient,
|
||||
type MigrationUpgradeClient,
|
||||
type ModelLogger,
|
||||
tryMigrate,
|
||||
tryUpgrade
|
||||
type ModelLogger
|
||||
} from '@hcengineering/model'
|
||||
import core from '@hcengineering/model-core'
|
||||
import guest from './plugin'
|
||||
|
||||
async function createSpace (tx: TxOperations): Promise<void> {
|
||||
const current = await tx.findOne(core.class.Space, {
|
||||
_id: guest.space.Links
|
||||
})
|
||||
if (current === undefined) {
|
||||
await tx.createDoc(
|
||||
core.class.Space,
|
||||
core.space.Space,
|
||||
{
|
||||
name: 'Links',
|
||||
description: 'Space for all guest links',
|
||||
private: false,
|
||||
archived: false,
|
||||
members: []
|
||||
},
|
||||
guest.space.Links
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async function createDefaults (client: MigrationUpgradeClient): Promise<void> {
|
||||
const txOp = new TxOperations(client, core.account.System)
|
||||
await createSpace(txOp)
|
||||
}
|
||||
|
||||
export const guestOperation: MigrateOperation = {
|
||||
async migrate (client: MigrationClient, logger: ModelLogger): Promise<void> {
|
||||
await tryMigrate(client, guestId, [
|
||||
@ -95,9 +64,12 @@ export const guestOperation: MigrateOperation = {
|
||||
async upgrade (client: MigrationUpgradeClient): Promise<void> {
|
||||
await tryUpgrade(client, guestId, [
|
||||
{
|
||||
state: 'create-defaults',
|
||||
state: 'create-defaults-v2',
|
||||
func: async (client) => {
|
||||
await createDefaults(client)
|
||||
await createDefaultSpace(client, guest.space.Links, {
|
||||
name: 'Links',
|
||||
description: 'Space for all guest links'
|
||||
})
|
||||
}
|
||||
}
|
||||
])
|
||||
|
@ -22,7 +22,8 @@ import {
|
||||
IndexKind,
|
||||
type Markup,
|
||||
type Ref,
|
||||
type Type
|
||||
type Type,
|
||||
AccountRole
|
||||
} from '@hcengineering/core'
|
||||
import {
|
||||
type Department,
|
||||
@ -194,6 +195,7 @@ export function createModel (builder: Builder): void {
|
||||
{
|
||||
label: hr.string.HRApplication,
|
||||
icon: hr.icon.HR,
|
||||
accessLevel: AccountRole.User,
|
||||
alias: hrId,
|
||||
hidden: false,
|
||||
component: hr.component.Schedule
|
||||
|
@ -13,62 +13,31 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import core, { TxOperations } from '@hcengineering/core'
|
||||
import { inventoryId } from '@hcengineering/inventory'
|
||||
import {
|
||||
createDefaultSpace,
|
||||
tryUpgrade,
|
||||
type MigrateOperation,
|
||||
type MigrationClient,
|
||||
type MigrationUpgradeClient
|
||||
} from '@hcengineering/model'
|
||||
import inventory from './plugin'
|
||||
import { inventoryId } from '@hcengineering/inventory'
|
||||
|
||||
async function createSpace (tx: TxOperations): Promise<void> {
|
||||
const categories = await tx.findOne(core.class.Space, {
|
||||
_id: inventory.space.Category
|
||||
})
|
||||
if (categories === undefined) {
|
||||
await tx.createDoc(
|
||||
core.class.Space,
|
||||
core.space.Space,
|
||||
{
|
||||
name: 'Categories',
|
||||
description: 'Categories',
|
||||
private: false,
|
||||
archived: false,
|
||||
members: []
|
||||
},
|
||||
inventory.space.Category
|
||||
)
|
||||
}
|
||||
const products = await tx.findOne(core.class.Space, {
|
||||
_id: inventory.space.Products
|
||||
})
|
||||
if (products === undefined) {
|
||||
await tx.createDoc(
|
||||
core.class.Space,
|
||||
core.space.Space,
|
||||
{
|
||||
name: 'Products',
|
||||
description: 'Products',
|
||||
private: false,
|
||||
archived: false,
|
||||
members: []
|
||||
},
|
||||
inventory.space.Products
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export const inventoryOperation: MigrateOperation = {
|
||||
async migrate (client: MigrationClient): Promise<void> {},
|
||||
async upgrade (client: MigrationUpgradeClient): Promise<void> {
|
||||
await tryUpgrade(client, inventoryId, [
|
||||
{
|
||||
state: 'create-defaults',
|
||||
state: 'create-defaults-v2',
|
||||
func: async (client) => {
|
||||
const tx = new TxOperations(client, core.account.System)
|
||||
await createSpace(tx)
|
||||
await createDefaultSpace(client, inventory.space.Category, {
|
||||
name: 'Categories',
|
||||
description: 'Space for all inventory categories'
|
||||
})
|
||||
await createDefaultSpace(client, inventory.space.Products, {
|
||||
name: 'Products',
|
||||
description: 'Space for all inventory products'
|
||||
})
|
||||
}
|
||||
}
|
||||
])
|
||||
|
@ -15,8 +15,8 @@
|
||||
|
||||
// To help typescript locate view plugin properly
|
||||
import activity from '@hcengineering/activity'
|
||||
import { type FindOptions, SortingOrder } from '@hcengineering/core'
|
||||
import { type Lead, leadId } from '@hcengineering/lead'
|
||||
import { AccountRole, SortingOrder, type FindOptions } from '@hcengineering/core'
|
||||
import { leadId, type Lead } from '@hcengineering/lead'
|
||||
import { type Builder } from '@hcengineering/model'
|
||||
import chunter from '@hcengineering/model-chunter'
|
||||
import contact from '@hcengineering/model-contact'
|
||||
@ -30,19 +30,17 @@ import notification from '@hcengineering/notification'
|
||||
import setting from '@hcengineering/setting'
|
||||
import { type ViewOptionsModel } from '@hcengineering/view'
|
||||
|
||||
import { TFunnel, TLead, TCustomer } from './types'
|
||||
import lead from './plugin'
|
||||
import { defineSpaceType } from './spaceType'
|
||||
import { TCustomer, TFunnel, TLead } from './types'
|
||||
|
||||
export { leadId } from '@hcengineering/lead'
|
||||
export { leadOperation } from './migration'
|
||||
export { default } from './plugin'
|
||||
export * from './types'
|
||||
export * from './spaceType'
|
||||
export * from './types'
|
||||
|
||||
export function createModel (builder: Builder): void {
|
||||
const archiveId = 'archive'
|
||||
|
||||
builder.createModel(TFunnel, TLead, TCustomer)
|
||||
|
||||
builder.mixin(lead.class.Lead, core.class.Class, activity.mixin.ActivityDoc, {})
|
||||
@ -116,6 +114,7 @@ export function createModel (builder: Builder): void {
|
||||
label: lead.string.Customers,
|
||||
icon: contact.icon.Person, // <-- Put contact general icon here.
|
||||
component: workbench.component.SpecialView,
|
||||
accessLevel: AccountRole.User,
|
||||
componentProps: {
|
||||
_class: lead.mixin.Customer,
|
||||
icon: lead.icon.Lead,
|
||||
@ -124,18 +123,22 @@ export function createModel (builder: Builder): void {
|
||||
position: 'top'
|
||||
},
|
||||
{
|
||||
id: archiveId,
|
||||
component: workbench.component.Archive,
|
||||
icon: view.icon.Archive,
|
||||
label: workbench.string.Archive,
|
||||
id: 'funnels',
|
||||
component: workbench.component.SpecialView,
|
||||
icon: view.icon.List,
|
||||
label: lead.string.Funnels,
|
||||
position: 'bottom',
|
||||
visibleIf: workbench.function.HasArchiveSpaces,
|
||||
spaceClass: lead.class.Funnel
|
||||
accessLevel: AccountRole.User,
|
||||
componentProps: {
|
||||
_class: lead.class.Funnel,
|
||||
label: lead.string.Funnels,
|
||||
createComponent: lead.component.CreateFunnel,
|
||||
createLabel: lead.string.CreateFunnel
|
||||
}
|
||||
}
|
||||
],
|
||||
spaces: [
|
||||
{
|
||||
id: 'funnels',
|
||||
label: lead.string.Funnels,
|
||||
spaceClass: lead.class.Funnel,
|
||||
addSpaceLabel: lead.string.CreateFunnel,
|
||||
@ -148,6 +151,21 @@ export function createModel (builder: Builder): void {
|
||||
lead.app.Lead
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
view.class.Viewlet,
|
||||
core.space.Model,
|
||||
{
|
||||
attachTo: lead.class.Funnel,
|
||||
descriptor: view.viewlet.Table,
|
||||
configOptions: {
|
||||
hiddenKeys: ['identifier', 'name', 'description'],
|
||||
sortable: true
|
||||
},
|
||||
config: ['', 'members', 'private', 'archived']
|
||||
},
|
||||
lead.viewlet.TableFunnel
|
||||
)
|
||||
|
||||
createAction(builder, { ...actionTemplates.archiveSpace, target: lead.class.Funnel })
|
||||
createAction(builder, { ...actionTemplates.unarchiveSpace, target: lead.class.Funnel })
|
||||
|
||||
|
@ -33,8 +33,7 @@ export default mergeIds(leadId, lead, {
|
||||
Title: '' as IntlString,
|
||||
ManageFunnelStatuses: '' as IntlString,
|
||||
GotoLeadApplication: '' as IntlString,
|
||||
ConfigDescription: '' as IntlString,
|
||||
EditFunnel: '' as IntlString
|
||||
ConfigDescription: '' as IntlString
|
||||
},
|
||||
component: {
|
||||
CreateLead: '' as AnyComponent,
|
||||
@ -47,6 +46,7 @@ export default mergeIds(leadId, lead, {
|
||||
},
|
||||
viewlet: {
|
||||
TableCustomer: '' as Ref<Viewlet>,
|
||||
TableFunnel: '' as Ref<Viewlet>,
|
||||
TableLead: '' as Ref<Viewlet>,
|
||||
ListLead: '' as Ref<Viewlet>,
|
||||
DashboardLead: '' as Ref<Viewlet>,
|
||||
|
@ -14,9 +14,8 @@
|
||||
//
|
||||
|
||||
import activity, { type ActivityMessage, type DocUpdateMessage } from '@hcengineering/activity'
|
||||
import core, {
|
||||
import {
|
||||
DOMAIN_TX,
|
||||
TxOperations,
|
||||
TxProcessor,
|
||||
generateId,
|
||||
type AttachedDoc,
|
||||
@ -29,6 +28,7 @@ import core, {
|
||||
type DocumentQuery
|
||||
} from '@hcengineering/core'
|
||||
import {
|
||||
createDefaultSpace,
|
||||
tryMigrate,
|
||||
tryUpgrade,
|
||||
type MigrateOperation,
|
||||
@ -52,27 +52,6 @@ interface InboxData {
|
||||
|
||||
const DOMAIN_ACTIVITY = 'activity' as Domain
|
||||
|
||||
async function createSpace (client: MigrationUpgradeClient): Promise<void> {
|
||||
const txop = new TxOperations(client, core.account.System)
|
||||
const currentTemplate = await txop.findOne(core.class.Space, {
|
||||
_id: notification.space.Notifications
|
||||
})
|
||||
if (currentTemplate === undefined) {
|
||||
await txop.createDoc(
|
||||
core.class.Space,
|
||||
core.space.Space,
|
||||
{
|
||||
name: 'Notification space',
|
||||
description: 'Notification space',
|
||||
private: false,
|
||||
archived: false,
|
||||
members: []
|
||||
},
|
||||
notification.space.Notifications
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async function getActivityMessages (
|
||||
client: MigrationClient,
|
||||
contexts: {
|
||||
@ -309,9 +288,12 @@ export const notificationOperation: MigrateOperation = {
|
||||
async upgrade (client: MigrationUpgradeClient): Promise<void> {
|
||||
await tryUpgrade(client, notificationId, [
|
||||
{
|
||||
state: 'create-defaults',
|
||||
state: 'create-defaults-v2',
|
||||
func: async (client) => {
|
||||
await createSpace(client)
|
||||
await createDefaultSpace(client, notification.space.Notifications, {
|
||||
name: 'Notifications',
|
||||
description: 'Space for all notifications'
|
||||
})
|
||||
}
|
||||
}
|
||||
])
|
||||
|
@ -13,49 +13,23 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { TxOperations } from '@hcengineering/core'
|
||||
import {
|
||||
createDefaultSpace,
|
||||
tryUpgrade,
|
||||
type MigrateOperation,
|
||||
type MigrationClient,
|
||||
type MigrationUpgradeClient
|
||||
} from '@hcengineering/model'
|
||||
import core from '@hcengineering/model-core'
|
||||
import preference, { preferenceId } from '@hcengineering/preference'
|
||||
|
||||
async function createSpace (tx: TxOperations): Promise<void> {
|
||||
const current = await tx.findOne(core.class.Space, {
|
||||
_id: preference.space.Preference
|
||||
})
|
||||
if (current === undefined) {
|
||||
await tx.createDoc(
|
||||
core.class.Space,
|
||||
core.space.Space,
|
||||
{
|
||||
name: 'Preference',
|
||||
description: 'Preference space',
|
||||
private: false,
|
||||
archived: false,
|
||||
members: []
|
||||
},
|
||||
preference.space.Preference
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async function createDefaults (tx: TxOperations): Promise<void> {
|
||||
await createSpace(tx)
|
||||
}
|
||||
|
||||
export const preferenceOperation: MigrateOperation = {
|
||||
async migrate (client: MigrationClient): Promise<void> {},
|
||||
async upgrade (client: MigrationUpgradeClient): Promise<void> {
|
||||
await tryUpgrade(client, preferenceId, [
|
||||
{
|
||||
state: 'create-defaults',
|
||||
state: 'create-defaults-v2',
|
||||
func: async (client) => {
|
||||
const ops = new TxOperations(client, core.account.System)
|
||||
await createDefaults(ops)
|
||||
await createDefaultSpace(client, preference.space.Preference, { name: 'Preference' })
|
||||
}
|
||||
}
|
||||
])
|
||||
|
@ -14,7 +14,7 @@
|
||||
//
|
||||
|
||||
import activity from '@hcengineering/activity'
|
||||
import { type Lookup, type Ref, SortingOrder } from '@hcengineering/core'
|
||||
import { AccountRole, SortingOrder, type Lookup, type Ref } from '@hcengineering/core'
|
||||
import { type Builder } from '@hcengineering/model'
|
||||
import attachment from '@hcengineering/model-attachment'
|
||||
import calendar from '@hcengineering/model-calendar'
|
||||
@ -26,36 +26,27 @@ import presentation from '@hcengineering/model-presentation'
|
||||
import tags from '@hcengineering/model-tags'
|
||||
import task, { actionTemplates } from '@hcengineering/model-task'
|
||||
import tracker from '@hcengineering/model-tracker'
|
||||
import view, { actionTemplates as viewTemplates, createAction, showColorsViewOption } from '@hcengineering/model-view'
|
||||
import workbench, { type Application, createNavigateAction } from '@hcengineering/model-workbench'
|
||||
import view, { createAction, showColorsViewOption, actionTemplates as viewTemplates } from '@hcengineering/model-view'
|
||||
import workbench, { createNavigateAction, type Application } from '@hcengineering/model-workbench'
|
||||
import notification from '@hcengineering/notification'
|
||||
import { type IntlString } from '@hcengineering/platform'
|
||||
import { type Applicant, recruitId } from '@hcengineering/recruit'
|
||||
import { recruitId, type Applicant } from '@hcengineering/recruit'
|
||||
import setting from '@hcengineering/setting'
|
||||
import { type KeyBinding, type ViewOptionModel, type ViewOptionsModel } from '@hcengineering/view'
|
||||
|
||||
import recruit from './plugin'
|
||||
import { createReviewModel, reviewTableConfig, reviewTableOptions } from './review'
|
||||
import {
|
||||
TApplicant,
|
||||
TApplicantMatch,
|
||||
TCandidate,
|
||||
TCandidates,
|
||||
TOpinion,
|
||||
TReview,
|
||||
TVacancy,
|
||||
TVacancyList
|
||||
} from './types'
|
||||
import { defineSpaceType } from './spaceType'
|
||||
import { TApplicant, TApplicantMatch, TCandidate, TOpinion, TReview, TVacancy, TVacancyList } from './types'
|
||||
|
||||
export { recruitId } from '@hcengineering/recruit'
|
||||
export { recruitOperation } from './migration'
|
||||
export { default } from './plugin'
|
||||
export * from './types'
|
||||
export * from './spaceType'
|
||||
export * from './types'
|
||||
|
||||
export function createModel (builder: Builder): void {
|
||||
builder.createModel(TVacancy, TCandidates, TCandidate, TApplicant, TReview, TOpinion, TVacancyList, TApplicantMatch)
|
||||
builder.createModel(TVacancy, TCandidate, TApplicant, TReview, TOpinion, TVacancyList, TApplicantMatch)
|
||||
|
||||
builder.mixin(recruit.class.Vacancy, core.class.Class, activity.mixin.ActivityDoc, {})
|
||||
builder.mixin(recruit.class.Applicant, core.class.Class, activity.mixin.ActivityDoc, {})
|
||||
@ -206,6 +197,7 @@ export function createModel (builder: Builder): void {
|
||||
component: workbench.component.SpecialView,
|
||||
icon: recruit.icon.Talents,
|
||||
label: recruit.string.Talents,
|
||||
accessLevel: AccountRole.User,
|
||||
componentProps: {
|
||||
_class: recruit.mixin.Candidate,
|
||||
icon: contact.icon.Person,
|
||||
@ -219,6 +211,7 @@ export function createModel (builder: Builder): void {
|
||||
{
|
||||
id: skillsId,
|
||||
component: recruit.component.SkillsView,
|
||||
accessLevel: AccountRole.User,
|
||||
icon: recruit.icon.Skills,
|
||||
label: recruit.string.SkillsLabel,
|
||||
createItemLabel: recruit.string.SkillCreateLabel,
|
||||
@ -373,8 +366,6 @@ export function createModel (builder: Builder): void {
|
||||
'comments',
|
||||
'$lookup.company',
|
||||
'$lookup.company.$lookup.channels',
|
||||
'location',
|
||||
'description',
|
||||
{
|
||||
key: '@applications.modifiedOn',
|
||||
label: core.string.ModifiedDate
|
||||
|
@ -17,6 +17,7 @@ import { getCategories } from '@anticrm/skillset'
|
||||
import core, { DOMAIN_TX, type Status, TxOperations, type Ref } from '@hcengineering/core'
|
||||
import {
|
||||
type ModelLogger,
|
||||
createDefaultSpace,
|
||||
createOrUpdate,
|
||||
tryMigrate,
|
||||
tryUpgrade,
|
||||
@ -58,10 +59,10 @@ export const recruitOperation: MigrateOperation = {
|
||||
async upgrade (client: MigrationUpgradeClient): Promise<void> {
|
||||
await tryUpgrade(client, recruitId, [
|
||||
{
|
||||
state: 'create-default-project',
|
||||
state: 'create-defaults-v2',
|
||||
func: async (client) => {
|
||||
const tx = new TxOperations(client, core.account.System)
|
||||
await createDefaults(tx)
|
||||
await createDefaults(client, tx)
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -172,8 +173,8 @@ async function migrateDefaultTypeMixins (client: MigrationClient): Promise<void>
|
||||
)
|
||||
}
|
||||
|
||||
async function createDefaults (tx: TxOperations): Promise<void> {
|
||||
await createSpaces(tx)
|
||||
async function createDefaults (client: MigrationUpgradeClient, tx: TxOperations): Promise<void> {
|
||||
await createDefaultSpace(client, recruit.space.Reviews, { name: 'Reviews' })
|
||||
|
||||
await createOrUpdate(
|
||||
tx,
|
||||
@ -210,43 +211,3 @@ async function createDefaults (tx: TxOperations): Promise<void> {
|
||||
await createSequence(tx, recruit.class.Applicant)
|
||||
await createSequence(tx, recruit.class.Vacancy)
|
||||
}
|
||||
|
||||
async function createSpaces (tx: TxOperations): Promise<void> {
|
||||
const current = await tx.findOne(core.class.Space, {
|
||||
_id: recruit.space.CandidatesPublic
|
||||
})
|
||||
if (current === undefined) {
|
||||
await tx.createDoc(
|
||||
recruit.class.Candidates,
|
||||
core.space.Space,
|
||||
{
|
||||
name: 'public',
|
||||
description: 'Public Candidates',
|
||||
private: false,
|
||||
members: [],
|
||||
archived: false
|
||||
},
|
||||
recruit.space.CandidatesPublic
|
||||
)
|
||||
}
|
||||
|
||||
const currentReviews = await tx.findOne(core.class.Space, {
|
||||
_id: recruit.space.Reviews
|
||||
})
|
||||
if (currentReviews === undefined) {
|
||||
await tx.createDoc(
|
||||
core.class.Space,
|
||||
core.space.Space,
|
||||
{
|
||||
name: 'Reviews',
|
||||
description: 'Public reviews',
|
||||
private: false,
|
||||
members: [],
|
||||
archived: false
|
||||
},
|
||||
recruit.space.Reviews
|
||||
)
|
||||
} else if (currentReviews.private) {
|
||||
await tx.update(currentReviews, { private: false })
|
||||
}
|
||||
}
|
||||
|
@ -15,15 +15,15 @@
|
||||
|
||||
import type { Employee, Organization } from '@hcengineering/contact'
|
||||
import {
|
||||
type Domain,
|
||||
Account,
|
||||
IndexKind,
|
||||
type Domain,
|
||||
type Markup,
|
||||
type Ref,
|
||||
type Status,
|
||||
type Timestamp,
|
||||
type RolesAssignment,
|
||||
type Role,
|
||||
Account
|
||||
type RolesAssignment,
|
||||
type Status,
|
||||
type Timestamp
|
||||
} from '@hcengineering/core'
|
||||
import {
|
||||
Collection,
|
||||
@ -45,7 +45,7 @@ import attachment from '@hcengineering/model-attachment'
|
||||
import calendar, { TEvent } from '@hcengineering/model-calendar'
|
||||
import chunter from '@hcengineering/model-chunter'
|
||||
import contact, { TOrganization, TPerson } from '@hcengineering/model-contact'
|
||||
import core, { TAttachedDoc, TSpace } from '@hcengineering/model-core'
|
||||
import core, { TAttachedDoc } from '@hcengineering/model-core'
|
||||
import tags from '@hcengineering/model-tags'
|
||||
import task, { DOMAIN_TASK, TProject, TTask } from '@hcengineering/model-task'
|
||||
import { getEmbeddedLabel } from '@hcengineering/platform'
|
||||
@ -53,7 +53,6 @@ import type {
|
||||
Applicant,
|
||||
ApplicantMatch,
|
||||
Candidate,
|
||||
Candidates,
|
||||
Opinion,
|
||||
Review,
|
||||
Vacancy,
|
||||
@ -90,10 +89,6 @@ export class TVacancy extends TProject implements Vacancy {
|
||||
number!: number
|
||||
}
|
||||
|
||||
@Model(recruit.class.Candidates, core.class.Space)
|
||||
@UX(recruit.string.TalentPools, recruit.icon.RecruitApplication)
|
||||
export class TCandidates extends TSpace implements Candidates {}
|
||||
|
||||
@Mixin(recruit.mixin.Candidate, contact.class.Person)
|
||||
@UX(recruit.string.Talent, recruit.icon.RecruitApplication, 'TLNT', 'name', undefined, recruit.string.Talents)
|
||||
export class TCandidate extends TPerson implements Candidate {
|
||||
|
@ -48,14 +48,7 @@ export function createModel (builder: Builder): void {
|
||||
component: contact.component.Avatar,
|
||||
props: ['avatar', 'name']
|
||||
},
|
||||
title: { props: ['name'] },
|
||||
scoring: [
|
||||
{
|
||||
attr: 'space',
|
||||
value: contact.space.Employee as string,
|
||||
boost: 2
|
||||
}
|
||||
]
|
||||
title: { props: ['name'] }
|
||||
},
|
||||
getSearchTitle: {
|
||||
name: serverContact.function.ContactNameProvider
|
||||
@ -78,6 +71,24 @@ export function createModel (builder: Builder): void {
|
||||
}
|
||||
})
|
||||
|
||||
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
|
||||
trigger: serverContact.trigger.OnEmployeeCreate,
|
||||
txMatch: {
|
||||
objectClass: contact.class.Person,
|
||||
_class: core.class.TxMixin,
|
||||
mixin: contact.mixin.Employee,
|
||||
'attributes.active': true
|
||||
}
|
||||
})
|
||||
|
||||
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
|
||||
trigger: serverContact.trigger.OnPersonAccountCreate,
|
||||
txMatch: {
|
||||
objectClass: contact.class.PersonAccount,
|
||||
_class: core.class.TxCreateDoc
|
||||
}
|
||||
})
|
||||
|
||||
builder.mixin(
|
||||
contact.templateField.CurrentEmployeeName,
|
||||
templates.class.TemplateField,
|
||||
|
@ -13,45 +13,24 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import core, { TxOperations } from '@hcengineering/core'
|
||||
import {
|
||||
createDefaultSpace,
|
||||
tryUpgrade,
|
||||
type MigrateOperation,
|
||||
type MigrationClient,
|
||||
type MigrationUpgradeClient
|
||||
} from '@hcengineering/model'
|
||||
import setting from './plugin'
|
||||
import { settingId } from '@hcengineering/setting'
|
||||
|
||||
async function createSpace (tx: TxOperations): Promise<void> {
|
||||
const current = await tx.findOne(core.class.Space, {
|
||||
_id: setting.space.Setting
|
||||
})
|
||||
if (current === undefined) {
|
||||
await tx.createDoc(
|
||||
core.class.Space,
|
||||
core.space.Space,
|
||||
{
|
||||
name: 'Setting',
|
||||
description: 'Setting space',
|
||||
private: false,
|
||||
archived: false,
|
||||
members: []
|
||||
},
|
||||
setting.space.Setting
|
||||
)
|
||||
}
|
||||
}
|
||||
import setting from './plugin'
|
||||
|
||||
export const settingOperation: MigrateOperation = {
|
||||
async migrate (client: MigrationClient): Promise<void> {},
|
||||
async upgrade (client: MigrationUpgradeClient): Promise<void> {
|
||||
await tryUpgrade(client, settingId, [
|
||||
{
|
||||
state: 'create-defaults',
|
||||
state: 'create-defaults-v2',
|
||||
func: async (client) => {
|
||||
const tx = new TxOperations(client, core.account.System)
|
||||
await createSpace(tx)
|
||||
await createDefaultSpace(client, setting.space.Setting, { name: 'Setting' })
|
||||
}
|
||||
}
|
||||
])
|
||||
|
@ -1,40 +1,21 @@
|
||||
import core, { TxOperations } from '@hcengineering/core'
|
||||
import {
|
||||
createDefaultSpace,
|
||||
tryUpgrade,
|
||||
type MigrateOperation,
|
||||
type MigrationClient,
|
||||
type MigrationUpgradeClient
|
||||
} from '@hcengineering/model'
|
||||
import tags from './plugin'
|
||||
import { tagsId } from '@hcengineering/tags'
|
||||
import tags from './plugin'
|
||||
|
||||
export const tagsOperation: MigrateOperation = {
|
||||
async migrate (client: MigrationClient): Promise<void> {},
|
||||
async upgrade (client: MigrationUpgradeClient): Promise<void> {
|
||||
await tryUpgrade(client, tagsId, [
|
||||
{
|
||||
state: 'create-defaults',
|
||||
state: 'create-defaults-v2',
|
||||
func: async (client) => {
|
||||
const tx = new TxOperations(client, core.account.System)
|
||||
const current = await tx.findOne(core.class.Space, {
|
||||
_id: tags.space.Tags
|
||||
})
|
||||
if (current === undefined) {
|
||||
await tx.createDoc(
|
||||
core.class.Space,
|
||||
core.space.Space,
|
||||
{
|
||||
name: 'Tags',
|
||||
description: 'Space for all tags',
|
||||
private: false,
|
||||
archived: false,
|
||||
members: []
|
||||
},
|
||||
tags.space.Tags
|
||||
)
|
||||
} else if (current.private) {
|
||||
await tx.update(current, { private: false })
|
||||
}
|
||||
await createDefaultSpace(client, tags.space.Tags, { name: 'Tags', description: 'Space for all tags' })
|
||||
}
|
||||
}
|
||||
])
|
||||
|
@ -13,40 +13,41 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import activity, { type DocUpdateMessage } from '@hcengineering/activity'
|
||||
import {
|
||||
type Attribute,
|
||||
type Space,
|
||||
type Status,
|
||||
type TxCreateDoc,
|
||||
DOMAIN_STATUS,
|
||||
DOMAIN_TX,
|
||||
TxOperations,
|
||||
type Attribute,
|
||||
type Class,
|
||||
type Doc,
|
||||
type Ref,
|
||||
DOMAIN_TX,
|
||||
DOMAIN_STATUS,
|
||||
type TxUpdateDoc,
|
||||
type TxCollectionCUD
|
||||
type Space,
|
||||
type Status,
|
||||
type TxCollectionCUD,
|
||||
type TxCreateDoc,
|
||||
type TxUpdateDoc
|
||||
} from '@hcengineering/core'
|
||||
import {
|
||||
type ModelLogger,
|
||||
createDefaultSpace,
|
||||
createOrUpdate,
|
||||
tryMigrate,
|
||||
tryUpgrade,
|
||||
type MigrateOperation,
|
||||
type MigrationClient,
|
||||
type MigrationUpgradeClient
|
||||
type MigrationUpgradeClient,
|
||||
type ModelLogger
|
||||
} from '@hcengineering/model'
|
||||
import activity, { type DocUpdateMessage } from '@hcengineering/activity'
|
||||
import { DOMAIN_ACTIVITY } from '@hcengineering/model-activity'
|
||||
import core, { DOMAIN_SPACE } from '@hcengineering/model-core'
|
||||
import tags from '@hcengineering/model-tags'
|
||||
import {
|
||||
taskId,
|
||||
type ProjectStatus,
|
||||
type ProjectType,
|
||||
type ProjectTypeDescriptor,
|
||||
type Task,
|
||||
type TaskType,
|
||||
taskId,
|
||||
type ProjectStatus
|
||||
type TaskType
|
||||
} from '@hcengineering/task'
|
||||
|
||||
import task from './plugin'
|
||||
@ -64,49 +65,9 @@ export async function createSequence (tx: TxOperations, _class: Ref<Class<Doc>>)
|
||||
}
|
||||
}
|
||||
|
||||
async function createDefaultSequence (tx: TxOperations): Promise<void> {
|
||||
const current = await tx.findOne(core.class.Space, {
|
||||
_id: task.space.Sequence
|
||||
})
|
||||
if (current === undefined) {
|
||||
await tx.createDoc(
|
||||
core.class.Space,
|
||||
core.space.Space,
|
||||
{
|
||||
name: 'Sequences',
|
||||
description: 'Internal space to store sequence numbers',
|
||||
members: [],
|
||||
private: false,
|
||||
archived: false
|
||||
},
|
||||
task.space.Sequence
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async function createDefaultStatesSpace (tx: TxOperations): Promise<void> {
|
||||
const current = await tx.findOne(core.class.Space, {
|
||||
_id: task.space.Statuses
|
||||
})
|
||||
if (current === undefined) {
|
||||
await tx.createDoc(
|
||||
core.class.Space,
|
||||
core.space.Space,
|
||||
{
|
||||
name: 'Statuses',
|
||||
description: 'Internal space to store all Statuses',
|
||||
members: [],
|
||||
private: false,
|
||||
archived: false
|
||||
},
|
||||
task.space.Statuses
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async function createDefaults (tx: TxOperations): Promise<void> {
|
||||
await createDefaultSequence(tx)
|
||||
await createDefaultStatesSpace(tx)
|
||||
async function createDefaults (client: MigrationUpgradeClient): Promise<void> {
|
||||
await createDefaultSpace(client, task.space.Sequence, { name: 'Sequences' })
|
||||
await createDefaultSpace(client, task.space.Statuses, { name: 'Statuses' })
|
||||
}
|
||||
|
||||
export async function migrateDefaultStatusesBase<T extends Task> (
|
||||
@ -609,11 +570,14 @@ export const taskOperation: MigrateOperation = {
|
||||
},
|
||||
async upgrade (client: MigrationUpgradeClient): Promise<void> {
|
||||
await tryUpgrade(client, taskId, [
|
||||
{
|
||||
state: 'defaults-v2',
|
||||
func: createDefaults
|
||||
},
|
||||
{
|
||||
state: 'u-task-001',
|
||||
func: async (client) => {
|
||||
const tx = new TxOperations(client, core.account.System)
|
||||
await createDefaults(tx)
|
||||
|
||||
await createOrUpdate(
|
||||
tx,
|
||||
|
@ -13,42 +13,30 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import core, { TxOperations } from '@hcengineering/core'
|
||||
import {
|
||||
createDefaultSpace,
|
||||
tryUpgrade,
|
||||
type MigrateOperation,
|
||||
type MigrationClient,
|
||||
type MigrationUpgradeClient
|
||||
} from '@hcengineering/model'
|
||||
import telegram from './plugin'
|
||||
import { telegramId } from '@hcengineering/telegram'
|
||||
import telegram from './plugin'
|
||||
|
||||
export async function createSpace (client: MigrationUpgradeClient): Promise<void> {
|
||||
await createDefaultSpace(client, telegram.space.Telegram, {
|
||||
name: 'Telegram',
|
||||
description: 'Space for all telegram messages'
|
||||
})
|
||||
}
|
||||
|
||||
export const telegramOperation: MigrateOperation = {
|
||||
async migrate (client: MigrationClient): Promise<void> {},
|
||||
async upgrade (client: MigrationUpgradeClient): Promise<void> {
|
||||
await tryUpgrade(client, telegramId, [
|
||||
{
|
||||
state: 'create-defaults',
|
||||
func: async (client) => {
|
||||
const tx = new TxOperations(client, core.account.System)
|
||||
const current = await tx.findOne(core.class.Space, {
|
||||
_id: telegram.space.Telegram
|
||||
})
|
||||
if (current === undefined) {
|
||||
await tx.createDoc(
|
||||
core.class.Space,
|
||||
core.space.Space,
|
||||
{
|
||||
name: 'Telegram',
|
||||
description: 'Space for all telegram messages',
|
||||
private: false,
|
||||
archived: false,
|
||||
members: []
|
||||
},
|
||||
telegram.space.Telegram
|
||||
)
|
||||
}
|
||||
}
|
||||
state: 'defaults-v2',
|
||||
func: createSpace
|
||||
}
|
||||
])
|
||||
}
|
||||
|
@ -43,12 +43,15 @@ export const templatesOperation: MigrateOperation = {
|
||||
description: 'Space for public templates',
|
||||
private: false,
|
||||
archived: false,
|
||||
members: []
|
||||
members: [],
|
||||
autoJoin: true
|
||||
},
|
||||
templates.space.Templates
|
||||
)
|
||||
} else if (current.private) {
|
||||
await tx.update(current, { private: false })
|
||||
} else if (current.autoJoin !== true) {
|
||||
await tx.update(current, { autoJoin: true })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,8 @@ import {
|
||||
type MigrationUpgradeClient,
|
||||
createOrUpdate,
|
||||
tryMigrate,
|
||||
tryUpgrade
|
||||
tryUpgrade,
|
||||
createDefaultSpace
|
||||
} from '@hcengineering/model'
|
||||
import { makeRank } from '@hcengineering/rank'
|
||||
import core from '@hcengineering/model-core'
|
||||
@ -149,26 +150,6 @@ async function migrateTodosRanks (client: TxOperations): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
async function createDefaultSpace (tx: TxOperations): Promise<void> {
|
||||
const current = await tx.findOne(core.class.Space, {
|
||||
_id: time.space.ToDos
|
||||
})
|
||||
if (current === undefined) {
|
||||
await tx.createDoc(
|
||||
core.class.Space,
|
||||
core.space.Space,
|
||||
{
|
||||
name: 'Todos',
|
||||
description: 'Space for all todos',
|
||||
private: false,
|
||||
archived: false,
|
||||
members: []
|
||||
},
|
||||
time.space.ToDos
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async function fillProps (client: MigrationClient): Promise<void> {
|
||||
await client.update(
|
||||
DOMAIN_TIME,
|
||||
@ -196,11 +177,16 @@ export const timeOperation: MigrateOperation = {
|
||||
},
|
||||
async upgrade (client: MigrationUpgradeClient): Promise<void> {
|
||||
await tryUpgrade(client, timeId, [
|
||||
{
|
||||
state: 'create-defaults-v2',
|
||||
func: async (client) => {
|
||||
await createDefaultSpace(client, time.space.ToDos, { name: 'Todos', description: 'Space for all todos' })
|
||||
}
|
||||
},
|
||||
{
|
||||
state: 'u-time-0001',
|
||||
func: async (client) => {
|
||||
const tx = new TxOperations(client, core.account.System)
|
||||
await createDefaultSpace(tx)
|
||||
await createOrUpdate(
|
||||
tx,
|
||||
tags.class.TagCategory,
|
||||
|
@ -719,9 +719,6 @@ export function createActions (builder: Builder, issuesId: string, componentsId:
|
||||
},
|
||||
tracker.action.DeleteMilestone
|
||||
)
|
||||
builder.mixin(tracker.class.Project, core.class.Class, view.mixin.IgnoreActions, {
|
||||
actions: [view.action.Open]
|
||||
})
|
||||
builder.mixin(tracker.class.Milestone, core.class.Class, view.mixin.IgnoreActions, {
|
||||
actions: [view.action.Delete]
|
||||
})
|
||||
|
@ -329,14 +329,13 @@ function defineApplication (
|
||||
{
|
||||
id: 'all-projects',
|
||||
component: workbench.component.SpecialView,
|
||||
icon: view.icon.Archive,
|
||||
icon: view.icon.List,
|
||||
label: tracker.string.AllProjects,
|
||||
position: 'bottom',
|
||||
spaceClass: tracker.class.Project,
|
||||
componentProps: {
|
||||
_class: tracker.class.Project,
|
||||
label: tracker.string.AllProjects,
|
||||
icon: tracker.icon.Issues
|
||||
label: tracker.string.AllProjects
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -114,6 +114,7 @@ async function createDefaultProject (tx: TxOperations): Promise<void> {
|
||||
archived: false,
|
||||
identifier: 'TSK',
|
||||
sequence: 0,
|
||||
autoJoin: true,
|
||||
defaultIssueStatus: state._id,
|
||||
defaultTimeReportDay: TimeReportDayType.PreviousWorkDay,
|
||||
defaultAssignee: undefined,
|
||||
|
@ -523,37 +523,13 @@ export function defineViewlets (builder: Builder): void {
|
||||
core.space.Model,
|
||||
{
|
||||
attachTo: tracker.class.Project,
|
||||
descriptor: view.viewlet.List,
|
||||
viewOptions: {
|
||||
groupBy: ['createdBy'],
|
||||
orderBy: [
|
||||
['type', SortingOrder.Descending],
|
||||
['modifiedOn', SortingOrder.Descending],
|
||||
['createdOn', SortingOrder.Descending]
|
||||
],
|
||||
other: [showColorsViewOption]
|
||||
},
|
||||
descriptor: view.viewlet.Table,
|
||||
configOptions: {
|
||||
strict: true,
|
||||
hiddenKeys: ['label', 'description']
|
||||
hiddenKeys: ['identifier', 'name', 'description']
|
||||
},
|
||||
config: [
|
||||
{
|
||||
key: '',
|
||||
props: { kind: 'list' }
|
||||
},
|
||||
{ key: '', displayProps: { grow: true } },
|
||||
{
|
||||
key: '',
|
||||
presenter: tracker.component.MembersArrayEditor,
|
||||
sortingKey: 'members',
|
||||
props: { readonly: true, kind: 'list' }
|
||||
},
|
||||
// TODO: Need return type in future
|
||||
// {
|
||||
// key: 'type',
|
||||
// props: { kind: 'list' }
|
||||
// },
|
||||
'',
|
||||
'members',
|
||||
{
|
||||
key: 'defaultAssignee',
|
||||
props: { kind: 'list' }
|
||||
|
@ -197,6 +197,7 @@ export class TArrayEditor extends TClass implements ArrayEditor {
|
||||
@Mixin(view.mixin.AttributePresenter, core.class.Class)
|
||||
export class TAttributePresenter extends TClass implements AttributePresenter {
|
||||
presenter!: AnyComponent
|
||||
arrayPresenter?: AnyComponent
|
||||
}
|
||||
|
||||
@Mixin(view.mixin.AttributeFilterPresenter, core.class.Class)
|
||||
@ -1104,6 +1105,10 @@ export function createModel (builder: Builder): void {
|
||||
domain: DOMAIN_VIEW,
|
||||
disabled: [{ space: 1 }, { modifiedOn: 1 }, { modifiedBy: 1 }, { createdBy: 1 }, { createdOn: -1 }]
|
||||
})
|
||||
|
||||
builder.mixin(core.class.Space, core.class.Class, view.mixin.IgnoreActions, {
|
||||
actions: [view.action.Open, view.action.OpenInNewTab, view.action.Delete]
|
||||
})
|
||||
}
|
||||
|
||||
export default view
|
||||
|
@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { type Class, DOMAIN_MODEL, type Ref, type Space } from '@hcengineering/core'
|
||||
import { type Class, DOMAIN_MODEL, type Ref, type Space, type AccountRole } from '@hcengineering/core'
|
||||
import { type Builder, Mixin, Model, Prop, TypeRef, UX } from '@hcengineering/model'
|
||||
import preference, { TPreference } from '@hcengineering/model-preference'
|
||||
import { createAction } from '@hcengineering/model-view'
|
||||
@ -41,6 +41,7 @@ export class TApplication extends TDoc implements Application {
|
||||
alias!: string
|
||||
position?: 'top' | 'mid'
|
||||
hidden!: boolean
|
||||
accessLevel?: AccountRole
|
||||
}
|
||||
|
||||
@Model(workbench.class.ApplicationNavModel, core.class.Doc, DOMAIN_MODEL)
|
||||
|
@ -22,12 +22,10 @@ import workbench from '@hcengineering/workbench-resources/src/plugin'
|
||||
export default mergeIds(workbenchId, workbench, {
|
||||
component: {
|
||||
ApplicationPresenter: '' as AnyComponent,
|
||||
SpecialView: '' as AnyComponent,
|
||||
ServerManager: '' as AnyComponent
|
||||
},
|
||||
string: {
|
||||
Application: '' as IntlString,
|
||||
SpaceBrowser: '' as IntlString,
|
||||
HiddenApplication: '' as IntlString
|
||||
},
|
||||
function: {
|
||||
|
@ -367,8 +367,14 @@ export interface Space extends Doc {
|
||||
members: Arr<Ref<Account>>
|
||||
archived: boolean
|
||||
owners?: Ref<Account>[]
|
||||
autoJoin?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface SystemSpace extends Space {}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*
|
||||
@ -442,6 +448,7 @@ export interface Account extends Doc {
|
||||
* @public
|
||||
*/
|
||||
export enum AccountRole {
|
||||
DocGuest = 'DocGuest',
|
||||
Guest = 'GUEST',
|
||||
User = 'USER',
|
||||
Maintainer = 'MAINTAINER',
|
||||
@ -452,6 +459,7 @@ export enum AccountRole {
|
||||
* @public
|
||||
*/
|
||||
export const roleOrder: Record<AccountRole, number> = {
|
||||
[AccountRole.DocGuest]: 0,
|
||||
[AccountRole.Guest]: 1,
|
||||
[AccountRole.User]: 2,
|
||||
[AccountRole.Maintainer]: 3,
|
||||
|
@ -14,7 +14,7 @@
|
||||
//
|
||||
import type { IntlString, Plugin, StatusCode } from '@hcengineering/platform'
|
||||
import { plugin } from '@hcengineering/platform'
|
||||
import { Mixin, type Rank, Version } from '.'
|
||||
import { Mixin, Version, type Rank } from '.'
|
||||
import type {
|
||||
Account,
|
||||
AnyAttribute,
|
||||
@ -49,6 +49,7 @@ import type {
|
||||
Space,
|
||||
SpaceType,
|
||||
SpaceTypeDescriptor,
|
||||
SystemSpace,
|
||||
Timestamp,
|
||||
Type,
|
||||
TypeAny,
|
||||
@ -102,6 +103,7 @@ export default plugin(coreId, {
|
||||
TxUpdateDoc: '' as Ref<Class<TxUpdateDoc<Doc>>>,
|
||||
TxRemoveDoc: '' as Ref<Class<TxRemoveDoc<Doc>>>,
|
||||
Space: '' as Ref<Class<Space>>,
|
||||
SystemSpace: '' as Ref<Class<SystemSpace>>,
|
||||
TypedSpace: '' as Ref<Class<TypedSpace>>,
|
||||
SpaceTypeDescriptor: '' as Ref<Class<SpaceTypeDescriptor>>,
|
||||
SpaceType: '' as Ref<Class<SpaceType>>,
|
||||
|
@ -36,6 +36,7 @@ import {
|
||||
Permission,
|
||||
Ref,
|
||||
Role,
|
||||
roleOrder,
|
||||
Space,
|
||||
TypedSpace
|
||||
} from './classes'
|
||||
@ -773,6 +774,9 @@ export function reduceCalls<T extends (...args: ReduceParameters<T>) => Promise<
|
||||
|
||||
export function isOwnerOrMaintainer (): boolean {
|
||||
const account = getCurrentAccount()
|
||||
|
||||
return [AccountRole.Owner, AccountRole.Maintainer].includes(account.role)
|
||||
return hasAccountRole(account, AccountRole.Maintainer)
|
||||
}
|
||||
|
||||
export function hasAccountRole (acc: Account, targerRole: AccountRole): boolean {
|
||||
return roleOrder[acc.role] >= roleOrder[targerRole]
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import core, {
|
||||
Class,
|
||||
Client,
|
||||
DOMAIN_MIGRATION,
|
||||
Data,
|
||||
@ -13,6 +14,7 @@ import core, {
|
||||
ObjQueryType,
|
||||
PushOptions,
|
||||
Ref,
|
||||
Space,
|
||||
TxOperations,
|
||||
UnsetOptions,
|
||||
generateId
|
||||
@ -178,3 +180,37 @@ export async function tryUpgrade (
|
||||
await tx.createDoc(core.class.MigrationState, core.space.Configuration, st)
|
||||
}
|
||||
}
|
||||
|
||||
type DefaultSpaceData<T extends Space> = Pick<T, 'description' | 'private' | 'archived' | 'members'>
|
||||
type RequiredData<T extends Space> = Omit<Data<T>, keyof DefaultSpaceData<T>> & Partial<DefaultSpaceData<T>>
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function createDefaultSpace<T extends Space> (
|
||||
client: MigrationUpgradeClient,
|
||||
_id: Ref<T>,
|
||||
props: RequiredData<T>,
|
||||
_class: Ref<Class<T>> = core.class.SystemSpace
|
||||
): Promise<void> {
|
||||
const defaults: DefaultSpaceData<T> = {
|
||||
description: '',
|
||||
private: false,
|
||||
archived: false,
|
||||
members: []
|
||||
}
|
||||
const data: Data<Space> = {
|
||||
...defaults,
|
||||
...props
|
||||
}
|
||||
const tx = new TxOperations(client, core.account.System)
|
||||
const current = await tx.findOne(core.class.Space, {
|
||||
_id
|
||||
})
|
||||
if (current === undefined || current._class !== _class) {
|
||||
if (current !== undefined && current._class !== _class) {
|
||||
await tx.remove(current)
|
||||
}
|
||||
await tx.createDoc(_class, core.space.Space, data, _id)
|
||||
}
|
||||
}
|
||||
|
@ -1367,7 +1367,7 @@ export class LiveQuery implements WithTx, Client {
|
||||
private async changePrivateHandler (evt: TxWorkspaceEvent): Promise<void> {
|
||||
if (evt.event === WorkspaceEvent.SecurityChange) {
|
||||
for (const q of [...this.queue]) {
|
||||
if (typeof q.query.space !== 'string') {
|
||||
if (typeof q.query.space !== 'string' || q.query.space === evt.objectSpace) {
|
||||
if (!this.removeFromQueue(q)) {
|
||||
try {
|
||||
await this.refresh(q)
|
||||
@ -1380,7 +1380,7 @@ export class LiveQuery implements WithTx, Client {
|
||||
}
|
||||
for (const v of this.queries.values()) {
|
||||
for (const q of v) {
|
||||
if (typeof q.query.space !== 'string') {
|
||||
if (typeof q.query.space !== 'string' || q.query.space === evt.objectSpace) {
|
||||
try {
|
||||
await this.refresh(q)
|
||||
} catch (err: any) {
|
||||
|
@ -30,21 +30,21 @@
|
||||
$: icon = client.getHierarchy().getClass(value._class).icon
|
||||
</script>
|
||||
|
||||
{#if value && type === 'link'}
|
||||
<NavLink app={chunterId} space={value._id}>
|
||||
<div class="flex-presenter">
|
||||
{#if !inline && shouldShowAvatar}
|
||||
<div class="icon">
|
||||
{#if icon}
|
||||
<Icon {icon} size={'small'} />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
<span class="label">{value.name}</span>
|
||||
</div>
|
||||
</NavLink>
|
||||
{/if}
|
||||
|
||||
{#if value && type === 'text'}
|
||||
<span class="overflow-label" use:tooltip={{ label: getEmbeddedLabel(value.name) }}>{value.name}</span>
|
||||
{#if value}
|
||||
{#if type === 'link'}
|
||||
<NavLink app={chunterId} space={`${value._id}|${value._class}`}>
|
||||
<div class="flex-presenter">
|
||||
{#if !inline && shouldShowAvatar}
|
||||
<div class="icon">
|
||||
{#if icon}
|
||||
<Icon {icon} size={'small'} />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
<span class="label">{value.name}</span>
|
||||
</div>
|
||||
</NavLink>
|
||||
{:else}
|
||||
<span class="overflow-label" use:tooltip={{ label: getEmbeddedLabel(value.name) }}>{value.name}</span>
|
||||
{/if}
|
||||
{/if}
|
||||
|
@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Doc, Ref } from '@hcengineering/core'
|
||||
import { AccountRole, Doc, Ref, getCurrentAccount, hasAccountRole } from '@hcengineering/core'
|
||||
import { Scroller, SearchEdit, Label, ButtonIcon, IconAdd, showPopup, Menu } from '@hcengineering/ui'
|
||||
import { DocNotifyContext } from '@hcengineering/notification'
|
||||
import { SpecialNavModel } from '@hcengineering/workbench'
|
||||
@ -74,7 +74,9 @@
|
||||
<span class="overflow-label">
|
||||
<Label label={chunter.string.Chat} />
|
||||
</span>
|
||||
<ButtonIcon icon={IconAdd} kind={'primary'} size={'small'} on:click={addButtonClicked} />
|
||||
{#if hasAccountRole(getCurrentAccount(), AccountRole.User)}
|
||||
<ButtonIcon icon={IconAdd} kind={'primary'} size={'small'} on:click={addButtonClicked} />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#each chatSpecials as special, row}
|
||||
|
@ -1,257 +0,0 @@
|
||||
<!--
|
||||
// Copyright © 2023 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 {
|
||||
Class,
|
||||
DocumentQuery,
|
||||
FindOptions,
|
||||
getCurrentAccount,
|
||||
Ref,
|
||||
SortingOrder,
|
||||
SortingQuery,
|
||||
Space
|
||||
} from '@hcengineering/core'
|
||||
import { IntlString } from '@hcengineering/platform'
|
||||
import presentation, { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { AnyComponent, Button, Icon, Label, Scroller, SearchEdit, showPopup } from '@hcengineering/ui'
|
||||
import { FilterBar, FilterButton, SpacePresenter } from '@hcengineering/view-resources'
|
||||
import workbench from '@hcengineering/workbench'
|
||||
import { Channel } from '@hcengineering/chunter'
|
||||
import { InboxNotificationsClientImpl } from '@hcengineering/notification-resources'
|
||||
|
||||
import { openChannel } from '../../../navigation'
|
||||
import { getObjectIcon, joinChannel, leaveChannel } from '../../../utils'
|
||||
import chunter from './../../../plugin'
|
||||
|
||||
export let _class: Ref<Class<Channel>> = chunter.class.Channel
|
||||
export let label: IntlString
|
||||
export let createItemDialog: AnyComponent | undefined = undefined
|
||||
export let createItemLabel: IntlString = presentation.string.Create
|
||||
export let withHeader: boolean = true
|
||||
export let withFilterButton: boolean = true
|
||||
export let search: string = ''
|
||||
|
||||
const me = getCurrentAccount()._id
|
||||
const channelsQuery = createQuery()
|
||||
|
||||
const client = getClient()
|
||||
const notificationsClient = InboxNotificationsClientImpl.getClient()
|
||||
|
||||
const sort: SortingQuery<Space> = {
|
||||
name: SortingOrder.Ascending
|
||||
}
|
||||
|
||||
let searchQuery: DocumentQuery<Channel>
|
||||
let resultQuery: DocumentQuery<Channel>
|
||||
|
||||
let channels: Channel[] = []
|
||||
|
||||
$: updateSearchQuery(search)
|
||||
$: update(sort, resultQuery)
|
||||
|
||||
async function update (sort: SortingQuery<Channel>, resultQuery: DocumentQuery<Channel>): Promise<void> {
|
||||
const options: FindOptions<Channel> = {
|
||||
sort
|
||||
}
|
||||
|
||||
channelsQuery.query(
|
||||
_class,
|
||||
{
|
||||
...resultQuery,
|
||||
private: false
|
||||
},
|
||||
(res) => {
|
||||
channels = res
|
||||
},
|
||||
options
|
||||
)
|
||||
}
|
||||
|
||||
function updateSearchQuery (search: string): void {
|
||||
searchQuery = search.length ? { $search: search } : {}
|
||||
}
|
||||
|
||||
function showCreateDialog (_: Event) {
|
||||
showPopup(createItemDialog as AnyComponent, {}, 'middle')
|
||||
}
|
||||
|
||||
async function join (channel: Channel): Promise<void> {
|
||||
if (channel.members.includes(me)) {
|
||||
return
|
||||
}
|
||||
|
||||
await joinChannel(channel, me)
|
||||
}
|
||||
|
||||
async function leave (channel: Channel): Promise<void> {
|
||||
if (!channel.members.includes(me)) {
|
||||
return
|
||||
}
|
||||
await leaveChannel(channel, me)
|
||||
}
|
||||
|
||||
async function view (channel: Channel): Promise<void> {
|
||||
openChannel(channel._id, channel._class)
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if withHeader}
|
||||
<div class="ac-header full divide">
|
||||
<div class="ac-header__wrap-title">
|
||||
<span class="ac-header__title"><Label {label} /></span>
|
||||
</div>
|
||||
{#if createItemDialog}
|
||||
<div class="mb-1 clear-mins">
|
||||
<Button
|
||||
label={createItemLabel}
|
||||
kind={'primary'}
|
||||
size={'medium'}
|
||||
on:click={(ev) => {
|
||||
showCreateDialog(ev)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="ac-header full divide search-start">
|
||||
<div class="ac-header-full small-gap">
|
||||
<SearchEdit
|
||||
bind:value={search}
|
||||
on:change={() => {
|
||||
updateSearchQuery(search)
|
||||
update(sort, resultQuery)
|
||||
}}
|
||||
/>
|
||||
<!-- <ActionIcon icon={IconMoreH} size={'small'} /> -->
|
||||
<div class="buttons-divider" />
|
||||
{#if withFilterButton}
|
||||
<FilterButton {_class} />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{:else if withFilterButton}
|
||||
<div class="ac-header full divide">
|
||||
<div class="ac-header-full small-gap">
|
||||
<FilterButton {_class} />
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<FilterBar {_class} query={searchQuery} space={undefined} on:change={(e) => (resultQuery = e.detail)} />
|
||||
<Scroller padding={'2.5rem'}>
|
||||
<div class="spaces-container">
|
||||
{#each channels as channel (channel._id)}
|
||||
{@const icon = getObjectIcon(channel._class)}
|
||||
{@const joined = channel.members.includes(me)}
|
||||
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||
<div class="item flex-between" tabindex="0">
|
||||
<div class="flex-col clear-mins">
|
||||
<div class="fs-title flex-row-center">
|
||||
{#if icon}
|
||||
<div class="icon"><Icon {icon} size={'small'} /></div>
|
||||
{/if}
|
||||
<SpacePresenter value={channel} />
|
||||
</div>
|
||||
<div class="flex-row-center">
|
||||
{#if joined}
|
||||
<Label label={workbench.string.Joined} />
|
||||
·
|
||||
{/if}
|
||||
{channel.members.length}
|
||||
·
|
||||
{channel.description}
|
||||
</div>
|
||||
</div>
|
||||
<div class="tools flex-row-center gap-2">
|
||||
{#if joined}
|
||||
<Button
|
||||
size={'x-large'}
|
||||
label={workbench.string.Leave}
|
||||
on:click={async () => {
|
||||
await leave(channel)
|
||||
}}
|
||||
/>
|
||||
{:else}
|
||||
<Button
|
||||
size={'x-large'}
|
||||
label={workbench.string.View}
|
||||
on:click={async () => {
|
||||
await view(channel)
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
size={'x-large'}
|
||||
kind={'primary'}
|
||||
label={workbench.string.Join}
|
||||
on:click={async () => {
|
||||
await join(channel)
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{#if createItemDialog}
|
||||
<div class="flex-center mt-10">
|
||||
<Button
|
||||
size={'x-large'}
|
||||
kind={'primary'}
|
||||
label={createItemLabel}
|
||||
on:click={(ev) => {
|
||||
showCreateDialog(ev)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</Scroller>
|
||||
|
||||
<style lang="scss">
|
||||
.spaces-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 1px solid var(--theme-list-border-color);
|
||||
border-radius: 0.25rem;
|
||||
|
||||
.item {
|
||||
padding: 1rem 0.75rem;
|
||||
color: var(--theme-caption-color);
|
||||
cursor: pointer;
|
||||
|
||||
.icon {
|
||||
margin-right: 0.375rem;
|
||||
color: var(--theme-trans-color);
|
||||
}
|
||||
&:not(:last-child) {
|
||||
border-bottom: 1px solid var(--theme-divider-color);
|
||||
}
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: var(--highlight-hover);
|
||||
|
||||
.icon {
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
.tools {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
.tools {
|
||||
position: relative;
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -17,7 +17,6 @@
|
||||
import { FileBrowser } from '@hcengineering/attachment-resources'
|
||||
import { AnySvelteComponent, Button, Scroller } from '@hcengineering/ui'
|
||||
import workbench from '@hcengineering/workbench'
|
||||
import { SpaceBrowser } from '@hcengineering/workbench-resources'
|
||||
import contact from '@hcengineering/contact-resources/src/plugin'
|
||||
import { EmployeeBrowser } from '@hcengineering/contact-resources'
|
||||
import MessagesBrowser from './MessagesBrowser.svelte'
|
||||
@ -28,7 +27,6 @@
|
||||
import { SearchType } from '../../../utils'
|
||||
import plugin from '../../../plugin'
|
||||
import Header from '../../Header.svelte'
|
||||
import ChannelBrowser from './ChannelBrowser.svelte'
|
||||
|
||||
let userSearch_: string = ''
|
||||
userSearch.subscribe((v) => (userSearch_ = v))
|
||||
@ -42,16 +40,6 @@
|
||||
props?: Record<string, any>
|
||||
}[] = [
|
||||
{ searchType: SearchType.Messages, component: MessagesBrowser },
|
||||
{
|
||||
searchType: SearchType.Channels,
|
||||
component: ChannelBrowser,
|
||||
filterClass: plugin.class.Channel,
|
||||
props: {
|
||||
_class: plugin.class.Channel,
|
||||
label: plugin.string.ChannelBrowser,
|
||||
withFilterButton: false
|
||||
}
|
||||
},
|
||||
{
|
||||
searchType: SearchType.Files,
|
||||
component: FileBrowser,
|
||||
@ -95,16 +83,6 @@
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div class="ml-1 p-1 btn">
|
||||
<Button
|
||||
label={plugin.string.Channels}
|
||||
kind="ghost"
|
||||
selected={searchType === SearchType.Channels}
|
||||
on:click={() => {
|
||||
searchType = SearchType.Channels
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div class="ml-1 p-1 btn">
|
||||
<Button
|
||||
label={attachment.string.Files}
|
||||
|
@ -13,11 +13,21 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
import notification, { type DocNotifyContext } from '@hcengineering/notification'
|
||||
import { type Class, type Doc, generateId, type Ref, SortingOrder, type WithLookup } from '@hcengineering/core'
|
||||
import {
|
||||
type Class,
|
||||
type Doc,
|
||||
generateId,
|
||||
type Ref,
|
||||
SortingOrder,
|
||||
type WithLookup,
|
||||
hasAccountRole,
|
||||
getCurrentAccount,
|
||||
AccountRole
|
||||
} from '@hcengineering/core'
|
||||
import { createQuery, getClient, MessageBox } from '@hcengineering/presentation'
|
||||
import { get, writable } from 'svelte/store'
|
||||
import view from '@hcengineering/view'
|
||||
import { type SpecialNavModel } from '@hcengineering/workbench'
|
||||
import workbench, { type SpecialNavModel } from '@hcengineering/workbench'
|
||||
import attachment, { type SavedAttachments } from '@hcengineering/attachment'
|
||||
import activity, { type ActivityMessage } from '@hcengineering/activity'
|
||||
import { InboxNotificationsClientImpl } from '@hcengineering/notification-resources'
|
||||
@ -113,6 +123,19 @@ export const chatSpecials: SpecialNavModel[] = [
|
||||
icon: view.icon.Database,
|
||||
component: chunter.component.ChunterBrowser,
|
||||
position: 'top'
|
||||
},
|
||||
{
|
||||
id: 'channels',
|
||||
label: chunter.string.Channels,
|
||||
icon: view.icon.List,
|
||||
component: workbench.component.SpecialView,
|
||||
componentProps: {
|
||||
_class: chunter.class.Channel,
|
||||
label: chunter.string.Channels,
|
||||
createLabel: chunter.string.CreateChannel,
|
||||
createComponent: chunter.component.CreateChannel
|
||||
},
|
||||
position: 'top'
|
||||
}
|
||||
// TODO: Should be reworked or removed
|
||||
// {
|
||||
@ -246,27 +269,31 @@ async function unpinAllChannels (contexts: DocNotifyContext[]): Promise<void> {
|
||||
}
|
||||
|
||||
function getChannelsActions (): Action[] {
|
||||
return [
|
||||
{
|
||||
icon: chunter.icon.Hashtag,
|
||||
label: chunter.string.CreateChannel,
|
||||
action: async (): Promise<void> => {
|
||||
showPopup(chunter.component.CreateChannel, {}, 'top')
|
||||
}
|
||||
}
|
||||
]
|
||||
return hasAccountRole(getCurrentAccount(), AccountRole.User)
|
||||
? [
|
||||
{
|
||||
icon: chunter.icon.Hashtag,
|
||||
label: chunter.string.CreateChannel,
|
||||
action: async (): Promise<void> => {
|
||||
showPopup(chunter.component.CreateChannel, {}, 'top')
|
||||
}
|
||||
}
|
||||
]
|
||||
: []
|
||||
}
|
||||
|
||||
function getDirectActions (): Action[] {
|
||||
return [
|
||||
{
|
||||
label: chunter.string.NewDirectChat,
|
||||
icon: chunter.icon.Thread,
|
||||
action: async (): Promise<void> => {
|
||||
showPopup(chunter.component.CreateDirectChat, {}, 'top')
|
||||
}
|
||||
}
|
||||
]
|
||||
return hasAccountRole(getCurrentAccount(), AccountRole.User)
|
||||
? [
|
||||
{
|
||||
label: chunter.string.NewDirectChat,
|
||||
icon: chunter.icon.Thread,
|
||||
action: async (): Promise<void> => {
|
||||
showPopup(chunter.component.CreateDirectChat, {}, 'top')
|
||||
}
|
||||
}
|
||||
]
|
||||
: []
|
||||
}
|
||||
|
||||
function getActivityActions (contexts: DocNotifyContext[]): Action[] {
|
||||
|
@ -212,7 +212,6 @@ export async function ChannelTitleProvider (client: Client, id: Ref<Channel>): P
|
||||
|
||||
export enum SearchType {
|
||||
Messages,
|
||||
Channels,
|
||||
Files,
|
||||
Contacts
|
||||
}
|
||||
|
@ -102,6 +102,7 @@
|
||||
"Employees": "Employees",
|
||||
"People": "People",
|
||||
"For": "For",
|
||||
"SelectUsers": "Select users"
|
||||
"SelectUsers": "Select users",
|
||||
"AddGuest": "Add guest"
|
||||
}
|
||||
}
|
||||
|
@ -102,6 +102,7 @@
|
||||
"Employees": "Empleados",
|
||||
"People": "Personas",
|
||||
"For": "Para",
|
||||
"SelectUsers": "Seleccionar usuarios"
|
||||
"SelectUsers": "Seleccionar usuarios",
|
||||
"AddGuest": "Añadir invitado"
|
||||
}
|
||||
}
|
@ -102,6 +102,7 @@
|
||||
"Employees": "Funcionários",
|
||||
"People": "Pessoas",
|
||||
"For": "Para",
|
||||
"SelectUsers": "Selecionar utilizadores"
|
||||
"SelectUsers": "Selecionar utilizadores",
|
||||
"AddGuest": "Adicionar convidado"
|
||||
}
|
||||
}
|
@ -102,6 +102,7 @@
|
||||
"Employees": "Сотрудники",
|
||||
"People": "Люди",
|
||||
"For": "Для",
|
||||
"SelectUsers": "Выберите пользователей"
|
||||
"SelectUsers": "Выберите пользователей",
|
||||
"AddGuest": "Добавить гостя"
|
||||
}
|
||||
}
|
||||
|
@ -13,12 +13,13 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import contact, { Employee, PersonAccount } from '@hcengineering/contact'
|
||||
import { Employee, PersonAccount } from '@hcengineering/contact'
|
||||
import core, { Account, Ref } from '@hcengineering/core'
|
||||
import { IntlString } from '@hcengineering/platform'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { ButtonKind, ButtonSize } from '@hcengineering/ui'
|
||||
import { onDestroy } from 'svelte'
|
||||
import contact from '../plugin'
|
||||
import { personAccountByIdStore } from '../utils'
|
||||
import UserBoxList from './UserBoxList.svelte'
|
||||
|
||||
@ -32,6 +33,7 @@
|
||||
export let includeItems: Ref<Account>[] | undefined = undefined
|
||||
export let excludeItems: Ref<Account>[] | undefined = undefined
|
||||
export let emptyLabel: IntlString | undefined = undefined
|
||||
export let allowGuests: boolean = true
|
||||
|
||||
let timer: any = null
|
||||
const client = getClient()
|
||||
@ -104,6 +106,7 @@
|
||||
</script>
|
||||
|
||||
<UserBoxList
|
||||
_class={!allowGuests ? contact.mixin.Employee : contact.class.Person}
|
||||
items={employees}
|
||||
{label}
|
||||
{emptyLabel}
|
||||
@ -114,4 +117,5 @@
|
||||
justify={'left'}
|
||||
width={width ?? 'min-content'}
|
||||
{kind}
|
||||
create={allowGuests ? { component: contact.component.CreateGuest, label: contact.string.AddGuest } : undefined}
|
||||
/>
|
||||
|
@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Channel, combineName, Employee, Person, PersonAccount } from '@hcengineering/contact'
|
||||
import { Channel, combineName, Employee, PersonAccount } from '@hcengineering/contact'
|
||||
import core, { AccountRole, AttachedData, Data, generateId, Ref } from '@hcengineering/core'
|
||||
import login from '@hcengineering/login'
|
||||
import { getResource } from '@hcengineering/platform'
|
||||
@ -39,7 +39,11 @@
|
||||
return firstName === '' && lastName === '' && email === ''
|
||||
}
|
||||
|
||||
const object: Employee = {} as unknown as Employee
|
||||
const person: Data<Employee> = {
|
||||
name: '',
|
||||
city: '',
|
||||
active: true
|
||||
}
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const client = getClient()
|
||||
@ -47,11 +51,7 @@
|
||||
async function createPerson () {
|
||||
changeEmail()
|
||||
const name = combineName(firstName, lastName)
|
||||
const person: Data<Person> = {
|
||||
name,
|
||||
city: object.city
|
||||
}
|
||||
|
||||
person.name = name
|
||||
person.avatar = await avatarEditor.createAvatar()
|
||||
|
||||
await client.createDoc(contact.class.Person, contact.space.Contacts, person, id)
|
||||
@ -68,7 +68,7 @@
|
||||
})
|
||||
|
||||
const sendInvite = await getResource(login.function.SendInvite)
|
||||
await sendInvite(email.trim())
|
||||
await sendInvite(email.trim(), id, AccountRole.User)
|
||||
|
||||
for (const channel of channels) {
|
||||
await client.addCollection(contact.class.Channel, contact.space.Contacts, id, contact.class.Person, 'channels', {
|
||||
@ -82,12 +82,7 @@
|
||||
dispatch('close')
|
||||
}
|
||||
|
||||
let channels: AttachedData<Channel>[] = [
|
||||
{
|
||||
provider: contact.channelProvider.Email,
|
||||
value: ''
|
||||
}
|
||||
]
|
||||
let channels: AttachedData<Channel>[] = []
|
||||
|
||||
let exists: PersonAccount | undefined
|
||||
const query = createQuery()
|
||||
@ -170,7 +165,7 @@
|
||||
</div>
|
||||
<div class="ml-4">
|
||||
<EditableAvatar
|
||||
avatar={object.avatar}
|
||||
avatar={person.avatar}
|
||||
name={combineName(firstName, lastName)}
|
||||
{email}
|
||||
size={'large'}
|
||||
|
167
plugins/contact-resources/src/components/CreateGuest.svelte
Normal file
167
plugins/contact-resources/src/components/CreateGuest.svelte
Normal file
@ -0,0 +1,167 @@
|
||||
<!--
|
||||
// Copyright © 2022 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Channel, combineName, Person, PersonAccount } from '@hcengineering/contact'
|
||||
import core, { AccountRole, AttachedData, Data, generateId, Ref } from '@hcengineering/core'
|
||||
import login from '@hcengineering/login'
|
||||
import { getResource } from '@hcengineering/platform'
|
||||
import { Card, createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { createFocusManager, EditBox, FocusHandler, IconInfo, Label } from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { ChannelsDropdown } from '..'
|
||||
import contact from '../plugin'
|
||||
|
||||
export let canSave: boolean = true
|
||||
export let onCreate: ((id: Ref<Person>) => Promise<void>) | undefined = undefined
|
||||
|
||||
let firstName = ''
|
||||
let lastName = ''
|
||||
let email = ''
|
||||
|
||||
const id: Ref<Person> = generateId()
|
||||
|
||||
export function canClose (): boolean {
|
||||
return firstName === '' && lastName === '' && email === ''
|
||||
}
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const client = getClient()
|
||||
|
||||
async function createPerson () {
|
||||
changeEmail()
|
||||
const name = combineName(firstName, lastName)
|
||||
const person: Data<Person> = {
|
||||
name,
|
||||
city: ''
|
||||
}
|
||||
|
||||
await client.createDoc(contact.class.Person, contact.space.Contacts, person, id)
|
||||
|
||||
const mail = email.trim()
|
||||
|
||||
await client.createDoc(contact.class.PersonAccount, core.space.Model, {
|
||||
email: mail,
|
||||
person: id,
|
||||
role: AccountRole.Guest
|
||||
})
|
||||
|
||||
const sendInvite = await getResource(login.function.SendInvite)
|
||||
await sendInvite(email.trim(), id, AccountRole.Guest)
|
||||
|
||||
for (const channel of channels) {
|
||||
await client.addCollection(contact.class.Channel, contact.space.Contacts, id, contact.class.Person, 'channels', {
|
||||
value: channel.value,
|
||||
provider: channel.provider
|
||||
})
|
||||
}
|
||||
if (onCreate) {
|
||||
await onCreate(id)
|
||||
}
|
||||
dispatch('close')
|
||||
}
|
||||
|
||||
let channels: AttachedData<Channel>[] = []
|
||||
|
||||
let exists: PersonAccount | undefined
|
||||
const query = createQuery()
|
||||
$: query.query(
|
||||
contact.class.PersonAccount,
|
||||
{
|
||||
email: email.trim()
|
||||
},
|
||||
(p) => {
|
||||
exists = p[0]
|
||||
}
|
||||
)
|
||||
|
||||
const manager = createFocusManager()
|
||||
|
||||
function changeEmail () {
|
||||
const index = channels.findIndex((p) => p.provider === contact.channelProvider.Email)
|
||||
if (index !== -1) {
|
||||
channels[index].value = email.trim()
|
||||
} else {
|
||||
channels.push({
|
||||
provider: contact.channelProvider.Email,
|
||||
value: email.trim()
|
||||
})
|
||||
}
|
||||
channels = channels
|
||||
}
|
||||
</script>
|
||||
|
||||
<FocusHandler {manager} />
|
||||
|
||||
<Card
|
||||
label={contact.string.AddGuest}
|
||||
okAction={createPerson}
|
||||
canSave={firstName.trim().length > 0 &&
|
||||
lastName.trim().length > 0 &&
|
||||
email.trim().length > 0 &&
|
||||
exists === undefined &&
|
||||
canSave}
|
||||
on:close={() => {
|
||||
dispatch('close')
|
||||
}}
|
||||
on:changeContent
|
||||
>
|
||||
<svelte:fragment slot="error">
|
||||
{#if exists !== undefined}
|
||||
<div class="flex-row-center error-color">
|
||||
<IconInfo size={'small'} />
|
||||
<span class="text-sm overflow-label ml-2">
|
||||
<Label label={contact.string.PersonAlreadyExists} />
|
||||
</span>
|
||||
</div>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
<div class="flex-row-center">
|
||||
<div class="flex-grow flex-col">
|
||||
<EditBox
|
||||
placeholder={contact.string.PersonFirstNamePlaceholder}
|
||||
bind:value={firstName}
|
||||
kind={'large-style'}
|
||||
autoFocus
|
||||
focusIndex={1}
|
||||
/>
|
||||
<EditBox
|
||||
placeholder={contact.string.PersonLastNamePlaceholder}
|
||||
bind:value={lastName}
|
||||
kind={'large-style'}
|
||||
focusIndex={2}
|
||||
/>
|
||||
<div class="mt-1">
|
||||
<EditBox
|
||||
placeholder={contact.string.Email}
|
||||
bind:value={email}
|
||||
kind={'small-style'}
|
||||
focusIndex={3}
|
||||
on:blur={changeEmail}
|
||||
/>
|
||||
</div>
|
||||
<slot name="extraControls" />
|
||||
</div>
|
||||
</div>
|
||||
<svelte:fragment slot="pool">
|
||||
<ChannelsDropdown
|
||||
bind:value={channels}
|
||||
focusIndex={10}
|
||||
kind={'regular'}
|
||||
size={'large'}
|
||||
editable
|
||||
restricted={[contact.channelProvider.Email]}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
</Card>
|
@ -23,7 +23,7 @@
|
||||
getFirstName,
|
||||
getLastName
|
||||
} from '@hcengineering/contact'
|
||||
import { AccountRole, Ref, getCurrentAccount, roleOrder } from '@hcengineering/core'
|
||||
import { AccountRole, Ref, getCurrentAccount, hasAccountRole } from '@hcengineering/core'
|
||||
import { AttributeEditor, createQuery, getClient } from '@hcengineering/presentation'
|
||||
import setting, { IntegrationType } from '@hcengineering/setting'
|
||||
import { EditBox, FocusHandler, Scroller, createFocusManager } from '@hcengineering/ui'
|
||||
@ -46,7 +46,7 @@
|
||||
let avatarEditor: EditableAvatar
|
||||
|
||||
$: owner = account.person === object._id
|
||||
$: editable = !readonly && (roleOrder[account.role] >= roleOrder[AccountRole.Maintainer] || owner)
|
||||
$: editable = !readonly && (hasAccountRole(account, AccountRole.Maintainer) || owner)
|
||||
let firstName = getFirstName(object.name)
|
||||
let lastName = getLastName(object.name)
|
||||
|
||||
|
@ -13,16 +13,16 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import contact, { Person, PersonAccount, Employee } from '@hcengineering/contact'
|
||||
import contact, { Employee, Person, PersonAccount } from '@hcengineering/contact'
|
||||
import {
|
||||
Account,
|
||||
AccountRole,
|
||||
DocumentQuery,
|
||||
getCurrentAccount,
|
||||
Ref,
|
||||
roleOrder,
|
||||
SortingOrder,
|
||||
Space
|
||||
Space,
|
||||
getCurrentAccount,
|
||||
hasAccountRole
|
||||
} from '@hcengineering/core'
|
||||
import { translate } from '@hcengineering/platform'
|
||||
import presentation, { getClient } from '@hcengineering/presentation'
|
||||
@ -86,7 +86,7 @@
|
||||
}
|
||||
|
||||
const account = getCurrentAccount()
|
||||
$: canRemove = roleOrder[account.role] >= roleOrder[AccountRole.Maintainer] && space.createdBy === account._id
|
||||
$: canRemove = hasAccountRole(account, AccountRole.Maintainer) || space.createdBy === account._id
|
||||
</script>
|
||||
|
||||
<div class="flex-row-reverse mb-3 mt-3"><SearchEdit bind:value={search} /></div>
|
||||
|
@ -13,15 +13,15 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import contact, { Employee } from '@hcengineering/contact'
|
||||
import contact, { Employee, Person } from '@hcengineering/contact'
|
||||
import type { Class, Doc, DocumentQuery, Ref } from '@hcengineering/core'
|
||||
import type { IntlString } from '@hcengineering/platform'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { ObjectCreate, getClient } from '@hcengineering/presentation'
|
||||
import type { ButtonKind, ButtonSize, TooltipAlignment } from '@hcengineering/ui'
|
||||
import { Button, Label, showPopup } from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import plugin from '../plugin'
|
||||
import { employeeByIdStore } from '../utils'
|
||||
import { personByIdStore } from '../utils'
|
||||
import CombineAvatars from './CombineAvatars.svelte'
|
||||
import UserInfo from './UserInfo.svelte'
|
||||
import UsersPopup from './UsersPopup.svelte'
|
||||
@ -39,22 +39,29 @@
|
||||
export let labelDirection: TooltipAlignment | undefined = undefined
|
||||
export let emptyLabel: IntlString = plugin.string.Members
|
||||
export let readonly: boolean = false
|
||||
export let create: ObjectCreate | undefined = undefined
|
||||
|
||||
function filter (items: Ref<Employee>[]): Ref<Employee>[] {
|
||||
return items.filter((it, idx, arr) => arr.indexOf(it) === idx)
|
||||
}
|
||||
|
||||
let persons: Employee[] = filter(items)
|
||||
.map((p) => $employeeByIdStore.get(p))
|
||||
let persons: Person[] = filter(items)
|
||||
.map((p) => $personByIdStore.get(p))
|
||||
.filter((p) => p !== undefined) as Employee[]
|
||||
$: persons = filter(items)
|
||||
.map((p) => $employeeByIdStore.get(p))
|
||||
.map((p) => $personByIdStore.get(p))
|
||||
.filter((p) => p !== undefined) as Employee[]
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const client = getClient()
|
||||
|
||||
async function addPerson (evt: Event): Promise<void> {
|
||||
const accounts = new Set(
|
||||
client
|
||||
.getModel()
|
||||
.findAllSync(contact.class.PersonAccount, {})
|
||||
.map((p) => p.person)
|
||||
)
|
||||
showPopup(
|
||||
UsersPopup,
|
||||
{
|
||||
@ -71,8 +78,10 @@
|
||||
const isSelected = items.some((selectedItem) => selectedItem === it._id)
|
||||
return isActive || isSelected
|
||||
}
|
||||
return accounts.has(it._id as Ref<Person>)
|
||||
},
|
||||
readonly
|
||||
readonly,
|
||||
create
|
||||
},
|
||||
evt.target as HTMLElement,
|
||||
undefined,
|
||||
|
@ -106,6 +106,7 @@ import IconAddMember from './components/icons/AddMember.svelte'
|
||||
import UserDetails from './components/UserDetails.svelte'
|
||||
import EditOrganizationPanel from './components/EditOrganizationPanel.svelte'
|
||||
import ChannelIcon from './components/ChannelIcon.svelte'
|
||||
import CreateGuest from './components/CreateGuest.svelte'
|
||||
|
||||
import contact from './plugin'
|
||||
import {
|
||||
@ -294,6 +295,7 @@ export default async (): Promise<Resources> => ({
|
||||
NameChangedActivityMessage
|
||||
},
|
||||
component: {
|
||||
CreateGuest,
|
||||
ContactArrayEditor,
|
||||
PersonEditor,
|
||||
OrganizationEditor,
|
||||
|
@ -79,7 +79,8 @@ export default mergeIds(contactId, contact, {
|
||||
DeleteEmployee: '' as IntlString,
|
||||
DeleteEmployeeDescr: '' as IntlString,
|
||||
HasMessagesIn: '' as IntlString,
|
||||
HasNewMessagesIn: '' as IntlString
|
||||
HasNewMessagesIn: '' as IntlString,
|
||||
AddGuest: '' as IntlString
|
||||
},
|
||||
function: {
|
||||
GetContactLink: '' as Resource<(doc: Doc, props: Record<string, any>) => Promise<Location>>,
|
||||
|
@ -21,16 +21,6 @@ import { TemplateField, TemplateFieldCategory } from '@hcengineering/templates'
|
||||
import type { AnyComponent, IconSize, ResolvedLocation } from '@hcengineering/ui'
|
||||
import { Action, FilterMode, Viewlet } from '@hcengineering/view'
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface Organizations extends Space {}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface Persons extends Space {}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
@ -174,10 +164,8 @@ export const contactPlugin = plugin(contactId, {
|
||||
Channel: '' as Ref<Class<Channel>>,
|
||||
Contact: '' as Ref<Class<Contact>>,
|
||||
Person: '' as Ref<Class<Person>>,
|
||||
Persons: '' as Ref<Class<Persons>>,
|
||||
Member: '' as Ref<Class<Member>>,
|
||||
Organization: '' as Ref<Class<Organization>>,
|
||||
Organizations: '' as Ref<Class<Organizations>>,
|
||||
PersonAccount: '' as Ref<Class<PersonAccount>>,
|
||||
Status: '' as Ref<Class<Status>>,
|
||||
ContactsTab: '' as Ref<Class<ContactsTab>>
|
||||
@ -199,7 +187,8 @@ export const contactPlugin = plugin(contactId, {
|
||||
AccountArrayEditor: '' as AnyComponent,
|
||||
PersonIcon: '' as AnyComponent,
|
||||
EditOrganizationPanel: '' as AnyComponent,
|
||||
CollaborationUserAvatar: '' as AnyComponent
|
||||
CollaborationUserAvatar: '' as AnyComponent,
|
||||
CreateGuest: '' as AnyComponent
|
||||
},
|
||||
channelProvider: {
|
||||
Email: '' as Ref<ChannelProvider>,
|
||||
@ -251,7 +240,6 @@ export const contactPlugin = plugin(contactId, {
|
||||
KickUser: '' as Asset
|
||||
},
|
||||
space: {
|
||||
Employee: '' as Ref<Space>,
|
||||
Contacts: '' as Ref<Space>
|
||||
},
|
||||
app: {
|
||||
|
@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Ref, Space } from '@hcengineering/core'
|
||||
import { AccountRole, Ref, Space, getCurrentAccount, hasAccountRole } from '@hcengineering/core'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import {
|
||||
Button,
|
||||
@ -72,6 +72,13 @@
|
||||
await newTeamspace()
|
||||
}
|
||||
}
|
||||
|
||||
const dropdownItems = hasAccountRole(getCurrentAccount(), AccountRole.User)
|
||||
? [
|
||||
{ id: document.string.CreateDocument, label: document.string.CreateDocument },
|
||||
{ id: document.string.CreateTeamspace, label: document.string.CreateTeamspace }
|
||||
]
|
||||
: [{ id: document.string.CreateDocument, label: document.string.CreateDocument }]
|
||||
</script>
|
||||
|
||||
{#if loading}
|
||||
@ -87,10 +94,7 @@
|
||||
on:click={newDocument}
|
||||
mainButtonId={'new-document'}
|
||||
dropdownIcon={IconDropdown}
|
||||
dropdownItems={[
|
||||
{ id: document.string.CreateDocument, label: document.string.CreateDocument },
|
||||
{ id: document.string.CreateTeamspace, label: document.string.CreateTeamspace }
|
||||
]}
|
||||
{dropdownItems}
|
||||
on:dropdown-selected={(ev) => {
|
||||
void dropdownItemSelected(ev.detail)
|
||||
}}
|
||||
|
@ -14,36 +14,35 @@
|
||||
//
|
||||
|
||||
import {
|
||||
generateId,
|
||||
type Class,
|
||||
type Client,
|
||||
type DocumentQuery,
|
||||
type Ref,
|
||||
type RelatedDocument,
|
||||
type WithLookup,
|
||||
generateId,
|
||||
getCurrentAccount
|
||||
type WithLookup
|
||||
} from '@hcengineering/core'
|
||||
import { type Document, type Teamspace } from '@hcengineering/document'
|
||||
import { type Resources } from '@hcengineering/platform'
|
||||
import preference from '@hcengineering/preference'
|
||||
import { type ObjectSearchResult, getClient } from '@hcengineering/presentation'
|
||||
import { getClient, type ObjectSearchResult } from '@hcengineering/presentation'
|
||||
import { showPopup } from '@hcengineering/ui'
|
||||
import { openDoc } from '@hcengineering/view-resources'
|
||||
|
||||
import CreateDocument from './components/CreateDocument.svelte'
|
||||
import DocumentPresenter from './components/DocumentPresenter.svelte'
|
||||
import Documents from './components/Documents.svelte'
|
||||
import MyDocuments from './components/MyDocuments.svelte'
|
||||
import EditDoc from './components/EditDoc.svelte'
|
||||
import DocumentItem from './components/DocumentItem.svelte'
|
||||
import NewDocumentHeader from './components/NewDocumentHeader.svelte'
|
||||
import CreateTeamspace from './components/teamspace/CreateTeamspace.svelte'
|
||||
import TeamspaceSpacePresenter from './components/navigator/TeamspaceSpacePresenter.svelte'
|
||||
import DocumentSearchIcon from './components/DocumentSearchIcon.svelte'
|
||||
import NotificationDocumentPresenter from './components/NotificationDocumentPresenter.svelte'
|
||||
import Move from './components/Move.svelte'
|
||||
import DocumentToDoPresenter from './components/DocumentToDoPresenter.svelte'
|
||||
import DocumentIcon from './components/DocumentIcon.svelte'
|
||||
import DocumentItem from './components/DocumentItem.svelte'
|
||||
import DocumentPresenter from './components/DocumentPresenter.svelte'
|
||||
import DocumentSearchIcon from './components/DocumentSearchIcon.svelte'
|
||||
import DocumentToDoPresenter from './components/DocumentToDoPresenter.svelte'
|
||||
import Documents from './components/Documents.svelte'
|
||||
import EditDoc from './components/EditDoc.svelte'
|
||||
import Move from './components/Move.svelte'
|
||||
import MyDocuments from './components/MyDocuments.svelte'
|
||||
import NewDocumentHeader from './components/NewDocumentHeader.svelte'
|
||||
import NotificationDocumentPresenter from './components/NotificationDocumentPresenter.svelte'
|
||||
import TeamspaceSpacePresenter from './components/navigator/TeamspaceSpacePresenter.svelte'
|
||||
import CreateTeamspace from './components/teamspace/CreateTeamspace.svelte'
|
||||
|
||||
import document from './plugin'
|
||||
import { createEmptyDocument, documentTitleProvider, getDocumentLink, getDocumentUrl, resolveLocation } from './utils'
|
||||
@ -154,7 +153,6 @@ export default async (): Promise<Resources> => ({
|
||||
function: {
|
||||
GetDocumentLink: getDocumentUrl,
|
||||
GetObjectLinkFragment: getDocumentLink,
|
||||
IsTeamspaceVisible: async (space: Teamspace) => !space.private || space.members.includes(getCurrentAccount()._id),
|
||||
DocumentTitleProvider: documentTitleProvider
|
||||
},
|
||||
resolver: {
|
||||
|
@ -14,8 +14,8 @@
|
||||
//
|
||||
|
||||
import { type Client, type Doc, type Ref } from '@hcengineering/core'
|
||||
import document, { type Teamspace, documentId } from '@hcengineering/document'
|
||||
import { type IntlString, type Resource, mergeIds } from '@hcengineering/platform'
|
||||
import document, { documentId } from '@hcengineering/document'
|
||||
import { mergeIds, type IntlString, type Resource } from '@hcengineering/platform'
|
||||
import { type AnyComponent, type Location } from '@hcengineering/ui'
|
||||
|
||||
export default mergeIds(documentId, document, {
|
||||
@ -29,8 +29,7 @@ export default mergeIds(documentId, document, {
|
||||
function: {
|
||||
DocumentTitleProvider: '' as Resource<<T extends Doc>(client: Client, ref: Ref<T>, doc?: T) => Promise<string>>,
|
||||
GetDocumentLink: '' as Resource<(doc: Doc, props: Record<string, any>) => Promise<string>>,
|
||||
GetObjectLinkFragment: '' as Resource<(doc: Doc, props: Record<string, any>) => Promise<Location>>,
|
||||
IsTeamspaceVisible: '' as Resource<(space: Teamspace) => Promise<boolean>>
|
||||
GetObjectLinkFragment: '' as Resource<(doc: Doc, props: Record<string, any>) => Promise<Location>>
|
||||
},
|
||||
string: {
|
||||
DocumentNamePlaceholder: '' as IntlString,
|
||||
|
@ -107,6 +107,7 @@ export default plugin(gmailId, {
|
||||
EmailNotification: '' as Ref<NotificationType>
|
||||
},
|
||||
space: {
|
||||
// todo remove, should be in contact
|
||||
Gmail: '' as Ref<Space>
|
||||
},
|
||||
metadata: {
|
||||
|
@ -15,10 +15,10 @@
|
||||
|
||||
import type { Contact, Employee, PersonAccount } from '@hcengineering/contact'
|
||||
import type { Arr, AttachedDoc, Class, Doc, Markup, Mixin, Ref, Space, Type } from '@hcengineering/core'
|
||||
import { NotificationType } from '@hcengineering/notification'
|
||||
import type { Asset, IntlString, Plugin } from '@hcengineering/platform'
|
||||
import { plugin } from '@hcengineering/platform'
|
||||
import { Viewlet } from '@hcengineering/view'
|
||||
import { NotificationType } from '@hcengineering/notification'
|
||||
|
||||
/**
|
||||
* @public
|
||||
|
@ -33,6 +33,7 @@
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
|
||||
import leadRes from '../plugin'
|
||||
import view from '@hcengineering/view'
|
||||
|
||||
export let funnel: Funnel | undefined = undefined
|
||||
const dispatch = createEventDispatcher()
|
||||
@ -163,7 +164,7 @@
|
||||
</script>
|
||||
|
||||
<SpaceCreateCard
|
||||
label={leadRes.string.CreateFunnel}
|
||||
label={funnel ? view.string.EdifFunnel : leadRes.string.CreateFunnel}
|
||||
okAction={save}
|
||||
okLabel={!isNew ? ui.string.Save : undefined}
|
||||
{canSave}
|
||||
|
@ -16,7 +16,17 @@
|
||||
<script lang="ts">
|
||||
import contact, { Contact } from '@hcengineering/contact'
|
||||
import { UserBox } from '@hcengineering/contact-resources'
|
||||
import { AttachedData, AttachedDoc, generateId, Ref, SortingOrder, Status as TaskStatus } from '@hcengineering/core'
|
||||
import {
|
||||
AccountRole,
|
||||
AttachedData,
|
||||
AttachedDoc,
|
||||
generateId,
|
||||
getCurrentAccount,
|
||||
hasAccountRole,
|
||||
Ref,
|
||||
SortingOrder,
|
||||
Status as TaskStatus
|
||||
} from '@hcengineering/core'
|
||||
import type { Customer, Funnel, Lead } from '@hcengineering/lead'
|
||||
import { OK, Status } from '@hcengineering/platform'
|
||||
import { Card, createQuery, getClient, InlineAttributeBar, SpaceSelector } from '@hcengineering/presentation'
|
||||
@ -140,10 +150,12 @@
|
||||
kind={'regular'}
|
||||
size={'large'}
|
||||
bind:space={_space}
|
||||
create={{
|
||||
component: lead.component.CreateFunnel,
|
||||
label: lead.string.CreateFunnel
|
||||
}}
|
||||
create={hasAccountRole(getCurrentAccount(), AccountRole.User)
|
||||
? {
|
||||
component: lead.component.CreateFunnel,
|
||||
label: lead.string.CreateFunnel
|
||||
}
|
||||
: undefined}
|
||||
/>
|
||||
<TaskKindSelector projectType={funnel?.type} bind:value={kind} baseClass={lead.class.Lead} />
|
||||
</svelte:fragment>
|
||||
|
@ -44,7 +44,8 @@ export default mergeIds(leadId, lead, {
|
||||
Assignee: '' as IntlString,
|
||||
UnAssign: '' as IntlString,
|
||||
FunnelMembers: '' as IntlString,
|
||||
RoleLabel: '' as IntlString
|
||||
RoleLabel: '' as IntlString,
|
||||
EditFunnel: '' as IntlString
|
||||
},
|
||||
component: {
|
||||
CreateCustomer: '' as AnyComponent,
|
||||
|
@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { AccountRole, getCurrentAccount, roleOrder, Timestamp } from '@hcengineering/core'
|
||||
import { AccountRole, getCurrentAccount, hasAccountRole, Timestamp } from '@hcengineering/core'
|
||||
import { loginId } from '@hcengineering/login'
|
||||
import { getMetadata } from '@hcengineering/platform'
|
||||
import presentation, { copyTextToClipboard, createQuery } from '@hcengineering/presentation'
|
||||
@ -22,18 +22,21 @@
|
||||
Button,
|
||||
EditBox,
|
||||
getCurrentLocation,
|
||||
Grid,
|
||||
Label,
|
||||
Loading,
|
||||
locationToUrl,
|
||||
MiniToggle,
|
||||
ticker,
|
||||
Grid
|
||||
ticker
|
||||
} from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import login from '../plugin'
|
||||
import { getInviteLink } from '../utils'
|
||||
import InviteWorkspace from './icons/InviteWorkspace.svelte'
|
||||
|
||||
export let role: AccountRole = AccountRole.User
|
||||
export let ignoreSettings: boolean = false
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
const query = createQuery()
|
||||
@ -44,22 +47,23 @@
|
||||
limit: number | undefined
|
||||
}
|
||||
|
||||
$: query.query(setting.class.InviteSettings, {}, (set) => {
|
||||
if (set !== undefined && set.length > 0) {
|
||||
expHours = set[0].expirationTime
|
||||
emailMask = set[0].emailMask
|
||||
limit = set[0].limit
|
||||
} else {
|
||||
expHours = 48
|
||||
limit = -1
|
||||
}
|
||||
if (limit === -1) noLimit = true
|
||||
defaultValues = {
|
||||
expirationTime: expHours,
|
||||
emailMask,
|
||||
limit
|
||||
}
|
||||
})
|
||||
$: !ignoreSettings &&
|
||||
query.query(setting.class.InviteSettings, {}, (set) => {
|
||||
if (set !== undefined && set.length > 0) {
|
||||
expHours = set[0].expirationTime
|
||||
emailMask = set[0].emailMask
|
||||
limit = set[0].limit
|
||||
} else {
|
||||
expHours = 48
|
||||
limit = -1
|
||||
}
|
||||
if (limit === -1) noLimit = true
|
||||
defaultValues = {
|
||||
expirationTime: expHours,
|
||||
emailMask,
|
||||
limit
|
||||
}
|
||||
})
|
||||
|
||||
function setToDefault (): void {
|
||||
expHours = defaultValues.expirationTime
|
||||
@ -67,9 +71,9 @@
|
||||
limit = defaultValues.limit
|
||||
}
|
||||
|
||||
async function getLink (expHours: number, mask: string, limit: number | undefined): Promise<void> {
|
||||
async function getLink (expHours: number, mask: string, limit: number | undefined, role: AccountRole): Promise<void> {
|
||||
loading = true
|
||||
const inviteId = await getInviteLink(expHours, mask, limit)
|
||||
const inviteId = await getInviteLink(expHours, mask, limit, role)
|
||||
const loc = getCurrentLocation()
|
||||
loc.path[0] = loginId
|
||||
loc.path[1] = 'join'
|
||||
@ -103,14 +107,14 @@
|
||||
copiedTime = Date.now()
|
||||
}
|
||||
|
||||
let expHours: number = 1
|
||||
let expHours: number = 48
|
||||
let emailMask: string = ''
|
||||
let limit: number | undefined = undefined
|
||||
let useDefault: boolean | undefined = true
|
||||
let noLimit: boolean = false
|
||||
const isOwnerOrMaintainer: boolean = roleOrder[getCurrentAccount().role] > roleOrder[AccountRole.Maintainer]
|
||||
const isOwnerOrMaintainer: boolean = hasAccountRole(getCurrentAccount(), AccountRole.Maintainer)
|
||||
let defaultValues: InviteParams = {
|
||||
expirationTime: 1,
|
||||
expirationTime: 48,
|
||||
emailMask: '',
|
||||
limit: undefined
|
||||
}
|
||||
@ -124,7 +128,7 @@
|
||||
<Label label={login.string.InviteDescription} />
|
||||
<InviteWorkspace size={'large'} />
|
||||
</div>
|
||||
{#if isOwnerOrMaintainer}
|
||||
{#if isOwnerOrMaintainer && !ignoreSettings}
|
||||
<Grid column={1} rowGap={1.5}>
|
||||
<MiniToggle
|
||||
bind:on={useDefault}
|
||||
@ -183,7 +187,7 @@
|
||||
size={'medium'}
|
||||
kind={'primary'}
|
||||
on:click={() => {
|
||||
;((limit !== undefined && limit > 0) || noLimit) && getLink(expHours, emailMask, limit)
|
||||
;((limit !== undefined && limit > 0) || noLimit) && getLink(expHours, emailMask, limit, role)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
@ -14,7 +14,7 @@
|
||||
//
|
||||
|
||||
import { Analytics } from '@hcengineering/analytics'
|
||||
import { concatLink } from '@hcengineering/core'
|
||||
import { AccountRole, type Doc, type Ref, concatLink } from '@hcengineering/core'
|
||||
import login, { type LoginInfo, type Workspace, type WorkspaceLoginInfo } from '@hcengineering/login'
|
||||
import {
|
||||
OK,
|
||||
@ -526,7 +526,13 @@ export async function checkJoined (inviteId: string): Promise<[Status, Workspace
|
||||
}
|
||||
}
|
||||
|
||||
export async function getInviteLink (expHours: number = 1, emailMask: string = '', limit: number = -1): Promise<string> {
|
||||
export async function getInviteLink (
|
||||
expHours: number,
|
||||
emailMask: string,
|
||||
limit: number,
|
||||
role: AccountRole = AccountRole.User,
|
||||
personId?: Ref<Doc>
|
||||
): Promise<string> {
|
||||
const accountsUrl = getMetadata(login.metadata.AccountsUrl)
|
||||
|
||||
const exp = expHours * 1000 * 60 * 60
|
||||
@ -544,9 +550,14 @@ export async function getInviteLink (expHours: number = 1, emailMask: string = '
|
||||
return ''
|
||||
}
|
||||
|
||||
const params = [exp, emailMask, limit, role]
|
||||
if (personId !== undefined) {
|
||||
params.push(personId)
|
||||
}
|
||||
|
||||
const request = {
|
||||
method: 'getInviteLink',
|
||||
params: [exp, emailMask, limit]
|
||||
params
|
||||
}
|
||||
|
||||
const response = await fetch(accountsUrl, {
|
||||
@ -724,7 +735,7 @@ export async function leaveWorkspace (email: string): Promise<void> {
|
||||
})
|
||||
}
|
||||
|
||||
export async function sendInvite (email: string): Promise<void> {
|
||||
export async function sendInvite (email: string, personId?: Ref<Doc>, role?: AccountRole): Promise<void> {
|
||||
const accountsUrl = getMetadata(login.metadata.AccountsUrl)
|
||||
|
||||
if (accountsUrl === undefined) {
|
||||
@ -740,9 +751,11 @@ export async function sendInvite (email: string): Promise<void> {
|
||||
}
|
||||
const token = getMetadata(presentation.metadata.Token) as string
|
||||
|
||||
const params = [email, personId, role]
|
||||
|
||||
const request = {
|
||||
method: 'sendInvite',
|
||||
params: [email]
|
||||
params
|
||||
}
|
||||
|
||||
await fetch(accountsUrl, {
|
||||
|
@ -32,6 +32,7 @@
|
||||
"@types/jest": "^29.5.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hcengineering/core": "^0.6.28",
|
||||
"@hcengineering/platform": "^0.6.9",
|
||||
"@hcengineering/ui": "^0.6.11"
|
||||
},
|
||||
|
@ -13,6 +13,7 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { Ref, Doc, AccountRole } from '@hcengineering/core'
|
||||
import type { Asset, IntlString, Metadata, Plugin, Resource, Status } from '@hcengineering/platform'
|
||||
import { plugin } from '@hcengineering/platform'
|
||||
import type { AnyComponent } from '@hcengineering/ui'
|
||||
@ -77,7 +78,7 @@ export default plugin(loginId, {
|
||||
InviteLimit: '' as IntlString
|
||||
},
|
||||
function: {
|
||||
SendInvite: '' as Resource<(email: string) => Promise<void>>,
|
||||
SendInvite: '' as Resource<(email: string, personId?: Ref<Doc>, role?: AccountRole) => Promise<void>>,
|
||||
LeaveWorkspace: '' as Resource<(email: string) => Promise<void>>,
|
||||
ChangePassword: '' as Resource<(oldPassword: string, password: string) => Promise<void>>,
|
||||
SelectWorkspace: '' as Resource<(workspace: string) => Promise<[Status, WorkspaceLoginInfo | undefined]>>,
|
||||
|
@ -30,7 +30,10 @@
|
||||
Space,
|
||||
fillDefaults,
|
||||
generateId,
|
||||
Status as TaskStatus
|
||||
Status as TaskStatus,
|
||||
AccountRole,
|
||||
getCurrentAccount,
|
||||
hasAccountRole
|
||||
} from '@hcengineering/core'
|
||||
import { OK, Resource, Severity, Status, getResource } from '@hcengineering/platform'
|
||||
import presentation, {
|
||||
@ -318,10 +321,12 @@
|
||||
spaceOptions={orgOptions}
|
||||
readonly={preserveVacancy}
|
||||
label={recruit.string.Vacancy}
|
||||
create={{
|
||||
component: recruit.component.CreateVacancy,
|
||||
label: recruit.string.CreateVacancy
|
||||
}}
|
||||
create={hasAccountRole(getCurrentAccount(), AccountRole.User)
|
||||
? {
|
||||
component: recruit.component.CreateVacancy,
|
||||
label: recruit.string.CreateVacancy
|
||||
}
|
||||
: undefined}
|
||||
bind:value={_space}
|
||||
component={VacancyOrgPresenter}
|
||||
componentProps={{ inline: true }}
|
||||
|
@ -19,35 +19,34 @@
|
||||
import core, {
|
||||
Account,
|
||||
Data,
|
||||
fillDefaults,
|
||||
FindResult,
|
||||
generateId,
|
||||
getCurrentAccount,
|
||||
Ref,
|
||||
Role,
|
||||
RolesAssignment,
|
||||
SortingOrder
|
||||
SortingOrder,
|
||||
fillDefaults,
|
||||
generateId,
|
||||
getCurrentAccount
|
||||
} from '@hcengineering/core'
|
||||
import { Card, createQuery, getClient, InlineAttributeBar, MessageBox } from '@hcengineering/presentation'
|
||||
import { getEmbeddedLabel } from '@hcengineering/platform'
|
||||
import { Card, InlineAttributeBar, MessageBox, createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { Vacancy as VacancyClass } from '@hcengineering/recruit'
|
||||
import tags from '@hcengineering/tags'
|
||||
import task, { makeRank, ProjectType } from '@hcengineering/task'
|
||||
import task, { ProjectType, makeRank } from '@hcengineering/task'
|
||||
import { selectedTypeStore, typeStore } from '@hcengineering/task-resources'
|
||||
import tracker, { Issue, IssueStatus, IssueTemplate, IssueTemplateData, Project } from '@hcengineering/tracker'
|
||||
import {
|
||||
Button,
|
||||
Component,
|
||||
createFocusManager,
|
||||
EditBox,
|
||||
FocusHandler,
|
||||
IconAttachment,
|
||||
createFocusManager,
|
||||
showPopup
|
||||
} from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import recruit from '../plugin'
|
||||
import Company from './icons/Company.svelte'
|
||||
import Vacancy from './icons/Vacancy.svelte'
|
||||
import { selectedTypeStore, typeStore } from '@hcengineering/task-resources'
|
||||
import { getEmbeddedLabel } from '@hcengineering/platform'
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@ -59,7 +58,7 @@
|
||||
|
||||
let appliedTemplateId: Ref<ProjectType> | undefined
|
||||
let objectId: Ref<VacancyClass> = generateId()
|
||||
let issueTemplates: FindResult<IssueTemplate> = []
|
||||
let issueTemplates: IssueTemplate[] = []
|
||||
let fullDescription: string = ''
|
||||
|
||||
export let company: Ref<Organization> | undefined
|
||||
@ -68,7 +67,7 @@
|
||||
let vacancyData: Data<VacancyClass> = {
|
||||
archived: false,
|
||||
description: '',
|
||||
members: [],
|
||||
members: [getCurrentAccount()._id],
|
||||
name: '',
|
||||
number: 0,
|
||||
private: false,
|
||||
@ -157,13 +156,16 @@
|
||||
if (taskType === undefined) {
|
||||
return
|
||||
}
|
||||
const number = (incResult as any).object.sequence
|
||||
|
||||
const identifier = `${project?.identifier}-${number}`
|
||||
const resId = await client.addCollection(tracker.class.Issue, space, parent, tracker.class.Issue, 'subIssues', {
|
||||
title: template.title + ` (${name})`,
|
||||
description: template.description,
|
||||
assignee: template.assignee,
|
||||
component: template.component,
|
||||
milestone: template.milestone,
|
||||
number: (incResult as any).object.sequence,
|
||||
number,
|
||||
status: project?.defaultIssueStatus as Ref<IssueStatus>,
|
||||
priority: template.priority,
|
||||
rank,
|
||||
@ -177,7 +179,8 @@
|
||||
reports: 0,
|
||||
relations: [{ _id: id, _class: recruit.class.Vacancy }],
|
||||
childInfo: [],
|
||||
kind: taskType._id
|
||||
kind: taskType._id,
|
||||
identifier
|
||||
})
|
||||
if ((template.labels?.length ?? 0) > 0) {
|
||||
const tagElements = await client.findAll(tags.class.TagElement, { _id: { $in: template.labels } })
|
||||
@ -216,7 +219,7 @@
|
||||
archived: false,
|
||||
number: (incResult as any).object.sequence,
|
||||
company,
|
||||
members: [],
|
||||
members: [getCurrentAccount()._id],
|
||||
owners: [getCurrentAccount()._id],
|
||||
type: typeId
|
||||
},
|
||||
|
@ -104,7 +104,7 @@
|
||||
}
|
||||
|
||||
function showCreateDialog () {
|
||||
showPopup(CreateOrganization, { space: recruit.space.CandidatesPublic }, 'top')
|
||||
showPopup(CreateOrganization, {}, 'top')
|
||||
}
|
||||
const applicationSorting = (a: Doc, b: Doc) =>
|
||||
(applications?.get(b._id as Ref<Organization>)?.count ?? 0) -
|
||||
|
@ -13,7 +13,15 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import core, { Doc, DocumentQuery, Ref, WithLookup } from '@hcengineering/core'
|
||||
import core, {
|
||||
AccountRole,
|
||||
Doc,
|
||||
DocumentQuery,
|
||||
Ref,
|
||||
WithLookup,
|
||||
getCurrentAccount,
|
||||
hasAccountRole
|
||||
} from '@hcengineering/core'
|
||||
import { createQuery } from '@hcengineering/presentation'
|
||||
import { Vacancy } from '@hcengineering/recruit'
|
||||
import { Button, Component, IconAdd, Label, Loading, SearchEdit, showPopup, tableToCSV } from '@hcengineering/ui'
|
||||
@ -59,7 +67,7 @@
|
||||
)
|
||||
|
||||
function showCreateDialog () {
|
||||
showPopup(CreateVacancy, { space: recruit.space.CandidatesPublic }, 'top')
|
||||
showPopup(CreateVacancy, {}, 'top')
|
||||
}
|
||||
const applicationSorting = (a: Doc, b: Doc) =>
|
||||
(applications?.get(b._id as Ref<Vacancy>)?.count ?? 0) - (applications?.get(a._id as Ref<Vacancy>)?.count ?? 0) ?? 0
|
||||
@ -151,7 +159,9 @@
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
<Button icon={IconAdd} label={recruit.string.VacancyCreateLabel} kind={'primary'} on:click={showCreateDialog} />
|
||||
{#if hasAccountRole(getCurrentAccount(), AccountRole.User)}
|
||||
<Button icon={IconAdd} label={recruit.string.VacancyCreateLabel} kind={'primary'} on:click={showCreateDialog} />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ac-header full divide search-start">
|
||||
|
@ -17,9 +17,9 @@
|
||||
import { getEmbeddedLabel } from '@hcengineering/platform'
|
||||
import { Vacancy } from '@hcengineering/recruit'
|
||||
import { Icon, getPlatformAvatarColorForTextDef, themeStore, tooltip } from '@hcengineering/ui'
|
||||
import { ObjectPresenterType } from '@hcengineering/view'
|
||||
import { DocNavLink, ObjectMention } from '@hcengineering/view-resources'
|
||||
import { createEventDispatcher, onMount } from 'svelte'
|
||||
import { ObjectPresenterType } from '@hcengineering/view'
|
||||
|
||||
import recruit from '../plugin'
|
||||
|
||||
@ -43,14 +43,16 @@
|
||||
{#if inline}
|
||||
<ObjectMention object={value} {disabled} {accent} {noUnderline} component={recruit.component.EditVacancy} />
|
||||
{:else if type === 'link'}
|
||||
<DocNavLink {disabled} object={value} {accent} {noUnderline} component={recruit.component.EditVacancy}>
|
||||
<div class="flex-presenter" use:tooltip={{ label: getEmbeddedLabel(value.name) }}>
|
||||
<div class="icon"><Icon icon={recruit.icon.Vacancy} size={'small'} /></div>
|
||||
<span class="label nowrap" class:no-underline={noUnderline || disabled} class:fs-bold={accent}>
|
||||
{value.name}
|
||||
</span>
|
||||
</div>
|
||||
</DocNavLink>
|
||||
<div class="flex-between flex-gap-2 w-full">
|
||||
<DocNavLink {disabled} object={value} {accent} {noUnderline} component={recruit.component.EditVacancy}>
|
||||
<div class="flex-presenter" use:tooltip={{ label: getEmbeddedLabel(value.name) }}>
|
||||
<div class="icon"><Icon icon={recruit.icon.Vacancy} size={'small'} /></div>
|
||||
<span class="label nowrap" class:no-underline={noUnderline || disabled} class:fs-bold={accent}>
|
||||
{value.name}
|
||||
</span>
|
||||
</div>
|
||||
</DocNavLink>
|
||||
</div>
|
||||
{:else if type === 'text'}
|
||||
<span class="overflow-label" use:tooltip={{ label: getEmbeddedLabel(value.name) }}>
|
||||
{value.name}
|
||||
|
@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { type Client, type Doc, type Ref, type Space } from '@hcengineering/core'
|
||||
import { type Client, type Doc, type Ref } from '@hcengineering/core'
|
||||
import type { IntlString, Resource, StatusCode } from '@hcengineering/platform'
|
||||
import { mergeIds } from '@hcengineering/platform'
|
||||
import { type ObjectSearchCategory, type ObjectSearchFactory } from '@hcengineering/presentation'
|
||||
@ -135,9 +135,6 @@ export default mergeIds(recruitId, recruit, {
|
||||
GetTalentIds: '' as IntlString,
|
||||
CreateNewSkills: '' as IntlString
|
||||
},
|
||||
space: {
|
||||
CandidatesPublic: '' as Ref<Space>
|
||||
},
|
||||
category: {
|
||||
Other: '' as Ref<TagCategory>,
|
||||
Category: '' as Ref<TagCategory>
|
||||
|
@ -13,13 +13,12 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { Calendar } from '@hcengineering/calendar'
|
||||
import type { Attribute, Class, Doc, Mixin, Ref, Status } from '@hcengineering/core'
|
||||
import type { Attribute, Class, Doc, Mixin, Ref, Space, Status } from '@hcengineering/core'
|
||||
import type { Asset, IntlString, Plugin, Resource } from '@hcengineering/platform'
|
||||
import { plugin } from '@hcengineering/platform'
|
||||
import type { ProjectTypeDescriptor, TaskType } from '@hcengineering/task'
|
||||
import { AnyComponent, ResolvedLocation } from '@hcengineering/ui'
|
||||
import type { Applicant, ApplicantMatch, Candidate, Candidates, Opinion, Review, Vacancy, VacancyList } from './types'
|
||||
import type { Applicant, ApplicantMatch, Candidate, Opinion, Review, Vacancy, VacancyList } from './types'
|
||||
|
||||
export * from './types'
|
||||
|
||||
@ -38,7 +37,6 @@ const recruit = plugin(recruitId, {
|
||||
class: {
|
||||
Applicant: '' as Ref<Class<Applicant>>,
|
||||
ApplicantMatch: '' as Ref<Class<ApplicantMatch>>,
|
||||
Candidates: '' as Ref<Class<Candidates>>,
|
||||
Vacancy: '' as Ref<Class<Vacancy>>,
|
||||
Review: '' as Ref<Class<Review>>,
|
||||
Opinion: '' as Ref<Class<Opinion>>
|
||||
@ -82,7 +80,7 @@ const recruit = plugin(recruitId, {
|
||||
Location: '' as Resource<(loc: Location) => Promise<ResolvedLocation | undefined>>
|
||||
},
|
||||
space: {
|
||||
Reviews: '' as Ref<Calendar>
|
||||
Reviews: '' as Ref<Space>
|
||||
},
|
||||
taskTypes: {
|
||||
Applicant: '' as Ref<TaskType>
|
||||
|
@ -15,13 +15,10 @@
|
||||
|
||||
import { Event } from '@hcengineering/calendar'
|
||||
import type { Channel, Organization, Person } from '@hcengineering/contact'
|
||||
import type { AttachedData, AttachedDoc, Markup, Ref, Space, Status, Timestamp } from '@hcengineering/core'
|
||||
import type { AttachedData, AttachedDoc, Markup, Ref, Status, Timestamp } from '@hcengineering/core'
|
||||
import { TagReference } from '@hcengineering/tags'
|
||||
import type { Project, Task } from '@hcengineering/task'
|
||||
|
||||
/** @public */
|
||||
export interface Candidates extends Space {}
|
||||
|
||||
/** @public */
|
||||
export interface Vacancy extends Project {
|
||||
fullDescription?: string
|
||||
|
@ -13,12 +13,12 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import contact, { PersonAccount } from '@hcengineering/contact'
|
||||
import { EmployeePresenter, personByIdStore } from '@hcengineering/contact-resources'
|
||||
import { AccountRole, SortingOrder, getCurrentAccount, roleOrder } from '@hcengineering/core'
|
||||
import { AccountRole, getCurrentAccount, hasAccountRole } from '@hcengineering/core'
|
||||
import presentation, { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { DropdownIntlItem, DropdownLabelsIntl, EditBox, Header, Breadcrumb, Scroller } from '@hcengineering/ui'
|
||||
import { Breadcrumb, DropdownIntlItem, DropdownLabelsIntl, EditBox, Header, Scroller } from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import setting from '../plugin'
|
||||
|
||||
export let visibleNav: boolean = true
|
||||
@ -73,7 +73,7 @@
|
||||
</div>
|
||||
<DropdownLabelsIntl
|
||||
label={setting.string.Role}
|
||||
disabled={roleOrder[account.role] > roleOrder[currentRole] ||
|
||||
disabled={!hasAccountRole(account, currentRole) ||
|
||||
(account.role === AccountRole.Owner && owners.length === 1)}
|
||||
kind={'primary'}
|
||||
size={'medium'}
|
||||
|
@ -14,31 +14,31 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { PersonAccount } from '@hcengineering/contact'
|
||||
import { AccountRole, getCurrentAccount, roleOrder } from '@hcengineering/core'
|
||||
import { AccountRole, getCurrentAccount, hasAccountRole } from '@hcengineering/core'
|
||||
import login, { loginId } from '@hcengineering/login'
|
||||
import { setMetadata } from '@hcengineering/platform'
|
||||
import presentation, { closeClient, createQuery } from '@hcengineering/presentation'
|
||||
import setting, { SettingsCategory } from '@hcengineering/setting'
|
||||
import {
|
||||
Component,
|
||||
Label,
|
||||
NavGroup,
|
||||
NavItem,
|
||||
Scroller,
|
||||
Separator,
|
||||
defineSeparators,
|
||||
settingsSeparators,
|
||||
fetchMetadataLocalStorage,
|
||||
getCurrentResolvedLocation,
|
||||
navigate,
|
||||
resolvedLocationStore,
|
||||
setMetadataLocalStorage,
|
||||
settingsSeparators,
|
||||
showPopup,
|
||||
Label,
|
||||
NavItem,
|
||||
NavGroup,
|
||||
type AnyComponent
|
||||
} from '@hcengineering/ui'
|
||||
import { NavFooter } from '@hcengineering/workbench-resources'
|
||||
import { ComponentType, onDestroy } from 'svelte'
|
||||
import { settingsStore, clearSettingsStore, type SettingsStore } from '../store'
|
||||
import { clearSettingsStore, settingsStore, type SettingsStore } from '../store'
|
||||
|
||||
export let visibleNav: boolean = true
|
||||
export let navFloat: boolean = false
|
||||
@ -57,7 +57,7 @@
|
||||
setting.class.SettingsCategory,
|
||||
{},
|
||||
(res) => {
|
||||
categories = roleOrder[account.role] > roleOrder[AccountRole.User] ? res : res.filter((p) => !p.secured)
|
||||
categories = hasAccountRole(account, AccountRole.Maintainer) ? res : res.filter((p) => !p.secured)
|
||||
category = findCategory(categoryId)
|
||||
},
|
||||
{ sort: { order: 1 } }
|
||||
|
@ -14,16 +14,16 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { PersonAccount } from '@hcengineering/contact'
|
||||
import { AccountRole, getCurrentAccount, roleOrder } from '@hcengineering/core'
|
||||
import { AccountRole, getCurrentAccount, hasAccountRole } from '@hcengineering/core'
|
||||
import { createQuery, isAdminUser } from '@hcengineering/presentation'
|
||||
import setting, { SettingsCategory } from '@hcengineering/setting'
|
||||
import {
|
||||
Component,
|
||||
Location,
|
||||
NavItem,
|
||||
getCurrentResolvedLocation,
|
||||
navigate,
|
||||
resolvedLocationStore,
|
||||
NavItem
|
||||
resolvedLocationStore
|
||||
} from '@hcengineering/ui'
|
||||
import { onDestroy } from 'svelte'
|
||||
import { clearSettingsStore } from '../store'
|
||||
@ -45,7 +45,7 @@
|
||||
setting.class.WorkspaceSettingCategory,
|
||||
{},
|
||||
(res) => {
|
||||
categories = roleOrder[account.role] > roleOrder[AccountRole.User] ? res : res.filter((p) => !p.secured)
|
||||
categories = hasAccountRole(account, AccountRole.Maintainer) ? res : res.filter((p) => !p.secured)
|
||||
if (!admin) {
|
||||
categories = categories.filter((p) => !(p.adminOnly ?? false))
|
||||
}
|
||||
|
@ -184,15 +184,6 @@ export interface ProjectTypeDescriptor extends SpaceTypeDescriptor {
|
||||
editor?: AnyComponent
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export enum TaskGrouping {
|
||||
State = 'state',
|
||||
Assignee = 'assignee',
|
||||
NoGrouping = '#no_category'
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
|
@ -87,6 +87,7 @@ export default plugin(telegramId, {
|
||||
SharedMessages: '' as Ref<Class<SharedTelegramMessages>>
|
||||
},
|
||||
space: {
|
||||
// todo should be removed
|
||||
Telegram: '' as Ref<Space>
|
||||
},
|
||||
templateField: {
|
||||
|
@ -16,7 +16,6 @@
|
||||
import { Ref, getCurrentAccount } from '@hcengineering/core'
|
||||
import { createQuery } from '@hcengineering/presentation'
|
||||
import task, { Project } from '@hcengineering/task'
|
||||
import tracker, { Project as TrackerProject } from '@hcengineering/tracker'
|
||||
import { Label, Separator } from '@hcengineering/ui'
|
||||
import { ObjectPresenter, TreeNode } from '@hcengineering/view-resources'
|
||||
import time from '../../plugin'
|
||||
@ -25,36 +24,19 @@
|
||||
export let appsDirection: 'vertical' | 'horizontal' = 'horizontal'
|
||||
export let selected: Ref<Project> | undefined = (localStorage.getItem('team_last_mode') as Ref<Project>) ?? undefined
|
||||
|
||||
let memberProjects: Project[] = []
|
||||
let projectsPublic: Project[] = []
|
||||
let projects: Project[] = []
|
||||
const projectsQuery = createQuery()
|
||||
|
||||
const publicQuery = createQuery()
|
||||
|
||||
$: projectsQuery.query(
|
||||
projectsQuery.query(
|
||||
task.class.Project,
|
||||
{
|
||||
archived: false,
|
||||
members: getCurrentAccount()._id
|
||||
},
|
||||
(result) => {
|
||||
memberProjects = result
|
||||
projects = result
|
||||
}
|
||||
)
|
||||
|
||||
$: publicQuery.query(
|
||||
tracker.class.Project,
|
||||
{
|
||||
_id: { $nin: memberProjects.map((it) => it._id as Ref<TrackerProject>) },
|
||||
archived: false,
|
||||
private: { $ne: true }
|
||||
},
|
||||
(result) => {
|
||||
projectsPublic = result
|
||||
}
|
||||
)
|
||||
|
||||
$: finalProjects = memberProjects.concat(projectsPublic)
|
||||
</script>
|
||||
|
||||
<div class="antiPanel-navigator {appsDirection === 'horizontal' ? 'portrait' : 'landscape'}">
|
||||
@ -64,7 +46,7 @@
|
||||
<Label label={time.string.Planner} />
|
||||
</div>
|
||||
<TreeNode _id={'projects-planning'} label={time.string.Team} node>
|
||||
{#each finalProjects as _project}
|
||||
{#each projects as _project}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
class="antiNav-element parent"
|
||||
|
@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Ref, Space } from '@hcengineering/core'
|
||||
import { AccountRole, Ref, Space, getCurrentAccount, hasAccountRole } from '@hcengineering/core'
|
||||
import { MultipleDraftController, getClient } from '@hcengineering/presentation'
|
||||
import { ButtonWithDropdown, IconAdd, IconDropdown, SelectPopupValueType, showPopup } from '@hcengineering/ui'
|
||||
import view from '@hcengineering/view'
|
||||
@ -41,16 +41,23 @@
|
||||
}
|
||||
|
||||
$: label = draftExists || !closed ? tracker.string.ResumeDraft : tracker.string.NewIssue
|
||||
$: dropdownItems = [
|
||||
{
|
||||
id: tracker.string.CreateProject,
|
||||
label: tracker.string.CreateProject
|
||||
},
|
||||
{
|
||||
id: tracker.string.NewIssue,
|
||||
label
|
||||
}
|
||||
]
|
||||
$: dropdownItems = hasAccountRole(getCurrentAccount(), AccountRole.User)
|
||||
? [
|
||||
{
|
||||
id: tracker.string.CreateProject,
|
||||
label: tracker.string.CreateProject
|
||||
},
|
||||
{
|
||||
id: tracker.string.NewIssue,
|
||||
label
|
||||
}
|
||||
]
|
||||
: [
|
||||
{
|
||||
id: tracker.string.NewIssue,
|
||||
label
|
||||
}
|
||||
]
|
||||
const client = getClient()
|
||||
|
||||
let keys: string[] | undefined = undefined
|
||||
|
@ -13,18 +13,21 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import presentation from '@hcengineering/presentation'
|
||||
import { Project } from '@hcengineering/tracker'
|
||||
import {
|
||||
Icon,
|
||||
IconWithEmoji,
|
||||
Label,
|
||||
getPlatformColorDef,
|
||||
getPlatformColorForTextDef,
|
||||
themeStore,
|
||||
Label
|
||||
showPopup,
|
||||
themeStore
|
||||
} from '@hcengineering/ui'
|
||||
import tracker from '../../plugin'
|
||||
import view from '@hcengineering/view'
|
||||
import presentation from '@hcengineering/presentation'
|
||||
import { canEditSpace } from '@hcengineering/view-resources'
|
||||
import { CreateProject } from '../..'
|
||||
import tracker from '../../plugin'
|
||||
|
||||
export let value: Project | undefined
|
||||
export let inline: boolean = false
|
||||
|
@ -18,13 +18,13 @@ import { Analytics } from '@hcengineering/analytics'
|
||||
import core, {
|
||||
AccountRole,
|
||||
getCurrentAccount,
|
||||
hasAccountRole,
|
||||
matchQuery,
|
||||
type Class,
|
||||
type Client,
|
||||
type Doc,
|
||||
type Ref,
|
||||
type WithLookup,
|
||||
roleOrder
|
||||
type WithLookup
|
||||
} from '@hcengineering/core'
|
||||
import { getResource } from '@hcengineering/platform'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
@ -172,7 +172,7 @@ export function filterActions (
|
||||
): Array<WithLookup<Action>> {
|
||||
let result: Array<WithLookup<Action>> = []
|
||||
const hierarchy = client.getHierarchy()
|
||||
const role = getCurrentAccount().role
|
||||
const me = getCurrentAccount()
|
||||
const clazz = hierarchy.getClass(doc._class)
|
||||
const ignoreActions = hierarchy.as(clazz, view.mixin.IgnoreActions)
|
||||
const ignore: Array<Ref<Action>> = getIgnoreActions(ignoreActions?.actions ?? [], doc)
|
||||
@ -199,7 +199,7 @@ export function filterActions (
|
||||
if (ignore.includes(action._id)) {
|
||||
continue
|
||||
}
|
||||
if (roleOrder[role] < roleOrder[AccountRole.Maintainer] && action.secured === true) {
|
||||
if (!hasAccountRole(me, AccountRole.Maintainer) && action.secured === true) {
|
||||
continue
|
||||
}
|
||||
if (
|
||||
|
@ -33,11 +33,44 @@ import DateEditor from './components/DateEditor.svelte'
|
||||
import DatePresenter from './components/DatePresenter.svelte'
|
||||
import DocAttributeBar from './components/DocAttributeBar.svelte'
|
||||
import DocNavLink from './components/DocNavLink.svelte'
|
||||
import DocReferencePresenter from './components/DocReferencePresenter.svelte'
|
||||
import EditBoxPopup from './components/EditBoxPopup.svelte'
|
||||
import EditDoc from './components/EditDoc.svelte'
|
||||
import EnumArrayEditor from './components/EnumArrayEditor.svelte'
|
||||
import EnumEditor from './components/EnumEditor.svelte'
|
||||
import EnumPresenter from './components/EnumPresenter.svelte'
|
||||
import HTMLEditor from './components/HTMLEditor.svelte'
|
||||
import HTMLPresenter from './components/HTMLPresenter.svelte'
|
||||
import HyperlinkEditor from './components/HyperlinkEditor.svelte'
|
||||
import HyperlinkEditorPopup from './components/HyperlinkEditorPopup.svelte'
|
||||
import HyperlinkPresenter from './components/HyperlinkPresenter.svelte'
|
||||
import IconPicker from './components/IconPicker.svelte'
|
||||
import IntlStringPresenter from './components/IntlStringPresenter.svelte'
|
||||
import MarkupDiffPresenter from './components/MarkupDiffPresenter.svelte'
|
||||
import MarkupEditor from './components/MarkupEditor.svelte'
|
||||
import MarkupEditorPopup from './components/MarkupEditorPopup.svelte'
|
||||
import MarkupPresenter from './components/MarkupPresenter.svelte'
|
||||
import Menu from './components/Menu.svelte'
|
||||
import NumberEditor from './components/NumberEditor.svelte'
|
||||
import NumberPresenter from './components/NumberPresenter.svelte'
|
||||
import ObjectIcon from './components/ObjectIcon.svelte'
|
||||
import ObjectMention from './components/ObjectMention.svelte'
|
||||
import ObjectPresenter from './components/ObjectPresenter.svelte'
|
||||
import RolePresenter from './components/RolePresenter.svelte'
|
||||
import SearchSelector from './components/SearchSelector.svelte'
|
||||
import SpaceHeader from './components/SpaceHeader.svelte'
|
||||
import SpacePresenter from './components/SpacePresenter.svelte'
|
||||
import SpaceRefPresenter from './components/SpaceRefPresenter.svelte'
|
||||
import SpaceTypeSelector from './components/SpaceTypeSelector.svelte'
|
||||
import StringEditor from './components/StringEditor.svelte'
|
||||
import StringPresenter from './components/StringPresenter.svelte'
|
||||
import Table from './components/Table.svelte'
|
||||
import TableBrowser from './components/TableBrowser.svelte'
|
||||
import TimestampPresenter from './components/TimestampPresenter.svelte'
|
||||
import UpDownNavigator from './components/UpDownNavigator.svelte'
|
||||
import ValueSelector from './components/ValueSelector.svelte'
|
||||
import ViewletContentView from './components/ViewletContentView.svelte'
|
||||
import ViewletSettingButton from './components/ViewletSettingButton.svelte'
|
||||
import ArrayFilter from './components/filter/ArrayFilter.svelte'
|
||||
import DateFilter from './components/filter/DateFilter.svelte'
|
||||
import DateFilterPresenter from './components/filter/DateFilterPresenter.svelte'
|
||||
@ -48,13 +81,6 @@ import StringFilter from './components/filter/StringFilter.svelte'
|
||||
import StringFilterPresenter from './components/filter/StringFilterPresenter.svelte'
|
||||
import TimestampFilter from './components/filter/TimestampFilter.svelte'
|
||||
import ValueFilter from './components/filter/ValueFilter.svelte'
|
||||
import HTMLEditor from './components/HTMLEditor.svelte'
|
||||
import HTMLPresenter from './components/HTMLPresenter.svelte'
|
||||
import HyperlinkEditor from './components/HyperlinkEditor.svelte'
|
||||
import HyperlinkEditorPopup from './components/HyperlinkEditorPopup.svelte'
|
||||
import HyperlinkPresenter from './components/HyperlinkPresenter.svelte'
|
||||
import IconPicker from './components/IconPicker.svelte'
|
||||
import IntlStringPresenter from './components/IntlStringPresenter.svelte'
|
||||
import GithubPresenter from './components/linkPresenters/GithubPresenter.svelte'
|
||||
import YoutubePresenter from './components/linkPresenters/YoutubePresenter.svelte'
|
||||
import DividerPresenter from './components/list/DividerPresenter.svelte'
|
||||
@ -62,37 +88,11 @@ import GrowPresenter from './components/list/GrowPresenter.svelte'
|
||||
import ListView from './components/list/ListView.svelte'
|
||||
import SortableList from './components/list/SortableList.svelte'
|
||||
import SortableListItem from './components/list/SortableListItem.svelte'
|
||||
import MarkupDiffPresenter from './components/MarkupDiffPresenter.svelte'
|
||||
import MarkupEditor from './components/MarkupEditor.svelte'
|
||||
import MarkupEditorPopup from './components/MarkupEditorPopup.svelte'
|
||||
import MarkupPresenter from './components/MarkupPresenter.svelte'
|
||||
import Menu from './components/Menu.svelte'
|
||||
import TreeElement from './components/navigator/TreeElement.svelte'
|
||||
import TreeItem from './components/navigator/TreeItem.svelte'
|
||||
import TreeNode from './components/navigator/TreeNode.svelte'
|
||||
import NumberEditor from './components/NumberEditor.svelte'
|
||||
import NumberPresenter from './components/NumberPresenter.svelte'
|
||||
import ObjectMention from './components/ObjectMention.svelte'
|
||||
import ObjectPresenter from './components/ObjectPresenter.svelte'
|
||||
import RolePresenter from './components/RolePresenter.svelte'
|
||||
import SearchSelector from './components/SearchSelector.svelte'
|
||||
import SpaceHeader from './components/SpaceHeader.svelte'
|
||||
import SpacePresenter from './components/SpacePresenter.svelte'
|
||||
import SpaceRefPresenter from './components/SpaceRefPresenter.svelte'
|
||||
import SpaceTypeSelector from './components/SpaceTypeSelector.svelte'
|
||||
import StatusPresenter from './components/status/StatusPresenter.svelte'
|
||||
import StatusRefPresenter from './components/status/StatusRefPresenter.svelte'
|
||||
import StringEditor from './components/StringEditor.svelte'
|
||||
import StringPresenter from './components/StringPresenter.svelte'
|
||||
import Table from './components/Table.svelte'
|
||||
import TableBrowser from './components/TableBrowser.svelte'
|
||||
import TimestampPresenter from './components/TimestampPresenter.svelte'
|
||||
import UpDownNavigator from './components/UpDownNavigator.svelte'
|
||||
import ValueSelector from './components/ValueSelector.svelte'
|
||||
import ViewletContentView from './components/ViewletContentView.svelte'
|
||||
import ViewletSettingButton from './components/ViewletSettingButton.svelte'
|
||||
import DocReferencePresenter from './components/DocReferencePresenter.svelte'
|
||||
import ObjectIcon from './components/ObjectIcon.svelte'
|
||||
|
||||
import {
|
||||
afterResult,
|
||||
@ -121,33 +121,34 @@ import { IndexedDocumentPreview } from '@hcengineering/presentation'
|
||||
import { AggregationMiddleware, AnalyticsMiddleware } from './middleware'
|
||||
import { showEmptyGroups } from './viewOptions'
|
||||
import { canArchiveSpace, canDeleteObject, canDeleteSpace, canEditSpace } from './visibilityTester'
|
||||
export { canArchiveSpace, canDeleteObject, canDeleteSpace, canEditSpace } from './visibilityTester'
|
||||
export { getActions, getContextActions, invokeAction, showMenu } from './actions'
|
||||
export { default as ActionButton } from './components/ActionButton.svelte'
|
||||
export { default as ActionHandler } from './components/ActionHandler.svelte'
|
||||
export { default as BaseDocPresenter } from './components/BaseDocPresenter.svelte'
|
||||
export { default as FilterButton } from './components/filter/FilterButton.svelte'
|
||||
export { default as FilterRemovedNotification } from './components/filter/FilterRemovedNotification.svelte'
|
||||
export { default as FixedColumn } from './components/FixedColumn.svelte'
|
||||
export { default as SourcePresenter } from './components/inference/SourcePresenter.svelte'
|
||||
export { default as LinkPresenter } from './components/LinkPresenter.svelte'
|
||||
export { default as List } from './components/list/List.svelte'
|
||||
export { default as MarkupDiffPresenter } from './components/MarkupDiffPresenter.svelte'
|
||||
export { default as MarkupPresenter } from './components/MarkupPresenter.svelte'
|
||||
export { default as MarkupPreviewPopup } from './components/MarkupPreviewPopup.svelte'
|
||||
export { default as ContextMenu } from './components/Menu.svelte'
|
||||
export { default as NavLink } from './components/navigator/NavLink.svelte'
|
||||
export { default as ObjectBox } from './components/ObjectBox.svelte'
|
||||
export { default as ObjectBoxPopup } from './components/ObjectBoxPopup.svelte'
|
||||
export { default as ObjectPresenter } from './components/ObjectPresenter.svelte'
|
||||
export { default as ObjectSearchBox } from './components/ObjectSearchBox.svelte'
|
||||
export { default as ParentsNavigator } from './components/ParentsNavigator.svelte'
|
||||
export { default as StatusPresenter } from './components/status/StatusPresenter.svelte'
|
||||
export { default as StatusRefPresenter } from './components/status/StatusRefPresenter.svelte'
|
||||
export { default as SpaceTypeSelector } from './components/SpaceTypeSelector.svelte'
|
||||
export { default as TableBrowser } from './components/TableBrowser.svelte'
|
||||
export { default as ValueSelector } from './components/ValueSelector.svelte'
|
||||
export { default as ViewletSelector } from './components/ViewletSelector.svelte'
|
||||
export { default as ViewletsSettingButton } from './components/ViewletsSettingButton.svelte'
|
||||
export { default as FilterButton } from './components/filter/FilterButton.svelte'
|
||||
export { default as FilterRemovedNotification } from './components/filter/FilterRemovedNotification.svelte'
|
||||
export { default as SourcePresenter } from './components/inference/SourcePresenter.svelte'
|
||||
export { default as List } from './components/list/List.svelte'
|
||||
export { default as NavLink } from './components/navigator/NavLink.svelte'
|
||||
export { default as StatusPresenter } from './components/status/StatusPresenter.svelte'
|
||||
export { default as StatusRefPresenter } from './components/status/StatusRefPresenter.svelte'
|
||||
|
||||
export * from './filter'
|
||||
export * from './middleware'
|
||||
@ -178,6 +179,7 @@ export {
|
||||
DateEditor,
|
||||
DocAttributeBar,
|
||||
DocNavLink,
|
||||
DocReferencePresenter,
|
||||
EditBoxPopup,
|
||||
EditDoc,
|
||||
EnumEditor,
|
||||
@ -189,6 +191,7 @@ export {
|
||||
Menu,
|
||||
NumberEditor,
|
||||
NumberPresenter,
|
||||
ObjectIcon,
|
||||
ObjectMention,
|
||||
SortableList,
|
||||
SortableListItem,
|
||||
@ -203,9 +206,7 @@ export {
|
||||
TreeNode,
|
||||
UpDownNavigator,
|
||||
ViewletContentView,
|
||||
ViewletSettingButton,
|
||||
DocReferencePresenter,
|
||||
ObjectIcon
|
||||
ViewletSettingButton
|
||||
}
|
||||
|
||||
function PositionElementAlignment (e?: Event): PopupAlignment | undefined {
|
||||
|
@ -81,6 +81,7 @@ import {
|
||||
type Location
|
||||
} from '@hcengineering/ui'
|
||||
import view, {
|
||||
type AttributePresenter,
|
||||
type AttributeModel,
|
||||
type BuildModelKey,
|
||||
type BuildModelOptions,
|
||||
@ -189,7 +190,10 @@ export async function getAttributePresenter (
|
||||
const isCollectionAttr = presenterClass.category === 'collection'
|
||||
const mixin = isCollectionAttr ? view.mixin.CollectionPresenter : actualMixinClass
|
||||
|
||||
let presenterMixin = hierarchy.classHierarchyMixin(presenterClass.attrClass, mixin)
|
||||
let presenterMixin: AttributePresenter | CollectionPresenter | undefined = hierarchy.classHierarchyMixin(
|
||||
presenterClass.attrClass,
|
||||
mixin
|
||||
)
|
||||
|
||||
if (presenterMixin?.presenter === undefined && mixinClass != null && mixin === mixinClass) {
|
||||
presenterMixin = hierarchy.classHierarchyMixin(presenterClass.attrClass, view.mixin.AttributePresenter)
|
||||
@ -197,7 +201,10 @@ export async function getAttributePresenter (
|
||||
|
||||
let presenter: AnySvelteComponent
|
||||
|
||||
if (presenterMixin?.presenter !== undefined) {
|
||||
const attributePresenter = presenterMixin as AttributePresenter
|
||||
if (presenterClass.category === 'array' && attributePresenter.arrayPresenter !== undefined) {
|
||||
presenter = await getResource(attributePresenter.arrayPresenter)
|
||||
} else if (presenterMixin?.presenter !== undefined) {
|
||||
presenter = await getResource(presenterMixin.presenter)
|
||||
} else if (presenterClass.attrClass === core.class.TypeAny) {
|
||||
const typeAny = attribute.type as TypeAny
|
||||
|
@ -181,6 +181,7 @@ export interface CollectionPresenter extends Class<Doc> {
|
||||
*/
|
||||
export interface AttributePresenter extends Class<Doc> {
|
||||
presenter: AnyComponent
|
||||
arrayPresenter?: AnyComponent
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -10,10 +10,6 @@
|
||||
"General": "General",
|
||||
"Members": "Members",
|
||||
"Application": "Application",
|
||||
"View": "View",
|
||||
"Leave": "Leave",
|
||||
"Joined": "Joined",
|
||||
"Join": "Join",
|
||||
"BrowseSpaces": "Browse spaces",
|
||||
"AccountDisabled": "Account is disabled",
|
||||
"AccountDisabledDescr": "Please contact the workspace administrator",
|
||||
|
@ -10,10 +10,6 @@
|
||||
"General": "General",
|
||||
"Members": "Miembros",
|
||||
"Application": "Aplicación",
|
||||
"View": "Ver",
|
||||
"Leave": "Salir",
|
||||
"Joined": "Unido",
|
||||
"Join": "Unirse",
|
||||
"BrowseSpaces": "Explorar Espacios",
|
||||
"AccountDisabled": "La cuenta está deshabilitada",
|
||||
"AccountDisabledDescr": "Por favor, contacte con el administrador del espacio de trabajo",
|
||||
|
@ -10,10 +10,6 @@
|
||||
"General": "Geral",
|
||||
"Members": "Membros",
|
||||
"Application": "Aplicação",
|
||||
"View": "Visualizar",
|
||||
"Leave": "Sair",
|
||||
"Joined": "Ingressou",
|
||||
"Join": "Ingressar",
|
||||
"BrowseSpaces": "Explorar Espaços",
|
||||
"AccountDisabled": "A conta está desabilitada",
|
||||
"AccountDisabledDescr": "Entre em contato com o administrador do espaço de trabalho",
|
||||
|
@ -10,10 +10,6 @@
|
||||
"General": "Общее",
|
||||
"Members": "Участники",
|
||||
"Application": "Приложение",
|
||||
"View": "Посмотреть",
|
||||
"Leave": "Покинуть",
|
||||
"Joined": "Вы присоединились",
|
||||
"Join": "Присоединиться",
|
||||
"BrowseSpaces": "Обзор пространств",
|
||||
"AccountDisabled": "Аккаунт отключен",
|
||||
"AccountDisabledDescr": "Пожалуйста, свяжитесь с администратором",
|
||||
|
@ -14,7 +14,7 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import contact, { Employee, PersonAccount, formatName } from '@hcengineering/contact'
|
||||
import { AccountRole, Ref, getCurrentAccount, roleOrder } from '@hcengineering/core'
|
||||
import { AccountRole, Ref, getCurrentAccount, hasAccountRole } from '@hcengineering/core'
|
||||
import login from '@hcengineering/login'
|
||||
import { createQuery } from '@hcengineering/presentation'
|
||||
import setting, { SettingsCategory, settingId } from '@hcengineering/setting'
|
||||
@ -41,7 +41,7 @@
|
||||
setting.class.SettingsCategory,
|
||||
{},
|
||||
(res) => {
|
||||
items = roleOrder[account.role] > roleOrder[AccountRole.User] ? res : res.filter((p) => !p.secured)
|
||||
items = hasAccountRole(getCurrentAccount(), AccountRole.Maintainer) ? res : res.filter((p) => !p.secured)
|
||||
},
|
||||
{ sort: { order: 1 } }
|
||||
)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user