TSK-1009: Configurable platform (#3055)

Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
Andrey Sobolev 2023-04-25 14:34:10 +07:00 committed by GitHub
parent 5c30b88976
commit aa218ab898
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
141 changed files with 1175 additions and 463 deletions

View File

@ -27,10 +27,12 @@ Before we could start we need to create workspace/account and associate it with
cd ./tool
rushx run-local create-workspace ws1 -o DevWorkspace # Create workspace
rushx run-local create-account user1 -p 1234 -f John -l Appleseed # Create account
rushx run-local assign-workspace user1 ws1 # Assign worksapce to user
rushx run-local configure sanity-ws --list --enable '*' # Enable all modules, then if they are not yet intended to be used by wide audience.
rushx run-local assign-workspace user1 ws1 # Assign workspace to user
```
Following URL http://localhost:8087/login:component:LoginApp will lead us to app in production mode.
Following URL http://localhost:8087 will lead us to app in production mode.
## Run in development mode
@ -39,7 +41,7 @@ cd dev/prod
rushx dev-server
```
Then go to http://localhost:8080/login:component:LoginApp
Then go to http://localhost:8080
## Update project structure and database
@ -51,6 +53,7 @@ rush build
```
It also might be required to upgrade running database.
```bash
cd ./dev/tool
rushx upgrade
@ -73,22 +76,12 @@ rush bundle
rush docker:build
## creates test docker containers and setups test database
./prepare.sh
## runs UI tests
## runs UI tests
rushx uitest
```
## Package publishing
```
npm login --registry=https://npm.pkg.github.com --scope=@hcengineering/anticrm
npm publish
```
### Libretranslate
```bash
pip install libretranslate
libretranslate --ssl --host 0.0.0.0 --port 4500 --load-only en,ru --update-models
node ./common/scripts/bump.js packageName
```

View File

@ -60,6 +60,7 @@ services:
- MINIO_SECRET_KEY=minioadmin
- FRONT_URL=http://front:8080
- SES_URL=http://localhost:8091
- MODEL_ENABLED=*
restart: unless-stopped
collaborator:
image: hardcoreeng/collaborator

View File

@ -13,7 +13,7 @@
// limitations under the License.
//
import { addLocation } from '@hcengineering/platform'
import { Plugin, addLocation } from '@hcengineering/platform'
import { activityId } from '@hcengineering/activity'
import { attachmentId } from '@hcengineering/attachment'
@ -21,7 +21,7 @@ import { automationId } from '@hcengineering/automation'
import { boardId } from '@hcengineering/board'
import { calendarId } from '@hcengineering/calendar'
import { chunterId } from '@hcengineering/chunter'
import { clientId } from '@hcengineering/client'
import client, { clientId } from '@hcengineering/client'
import { contactId } from '@hcengineering/contact'
import document, { documentId } from '@hcengineering/document'
import gmail, { gmailId } from '@hcengineering/gmail'
@ -153,6 +153,8 @@ export async function configurePlatform() {
addLocation(bitrixId, () => import(/* webpackChunkName: "bitrix" */ '@hcengineering/bitrix-resources'))
addLocation(requestId, () => import(/* webpackChunkName: "request" */ '@hcengineering/request-resources'))
setMetadata(client.metadata.FilterModel, true)
setMetadata(client.metadata.ExtraPlugins, ['preference' as Plugin])
setMetadata(workbench.metadata.PlatformTitle, 'Platform')
}

View File

@ -65,7 +65,7 @@ class InMemoryTxAdapter extends DummyDbAdapter implements TxAdapter {
}
async getModel (): Promise<Tx[]> {
return builder.getTxes()
return builder().getTxes()
}
}

View File

@ -16,29 +16,29 @@
import { prepareTools as prepareToolsRaw } from '@hcengineering/server-tool'
import { Data, Tx, Version } from '@hcengineering/core'
import { MinioService } from '@hcengineering/minio'
import { MigrateOperation } from '@hcengineering/model'
import builder, { migrateOperations, version } from '@hcengineering/model-all'
import { MinioService } from '@hcengineering/minio'
import { devTool } from '.'
import { addLocation } from '@hcengineering/platform'
import { serverAttachmentId } from '@hcengineering/server-attachment'
import { serverCalendarId } from '@hcengineering/server-calendar'
import { serverChunterId } from '@hcengineering/server-chunter'
import { serverContactId } from '@hcengineering/server-contact'
import { serverGmailId } from '@hcengineering/server-gmail'
import { serverHrId } from '@hcengineering/server-hr'
import { serverInventoryId } from '@hcengineering/server-inventory'
import { serverLeadId } from '@hcengineering/server-lead'
import { serverNotificationId } from '@hcengineering/server-notification'
import { serverRecruitId } from '@hcengineering/server-recruit'
import { serverRequestId } from '@hcengineering/server-request'
import { serverSettingId } from '@hcengineering/server-setting'
import { serverTagsId } from '@hcengineering/server-tags'
import { serverTaskId } from '@hcengineering/server-task'
import { serverTrackerId } from '@hcengineering/server-tracker'
import { serverTelegramId } from '@hcengineering/server-telegram'
import { serverHrId } from '@hcengineering/server-hr'
import { serverRequestId } from '@hcengineering/server-request'
import { serverTrackerId } from '@hcengineering/server-tracker'
import { serverViewId } from '@hcengineering/server-view'
import { addLocation } from '@hcengineering/platform'
addLocation(serverAttachmentId, () => import('@hcengineering/server-attachment-resources'))
addLocation(serverContactId, () => import('@hcengineering/server-contact-resources'))
@ -65,7 +65,9 @@ function prepareTools (): {
version: Data<Version>
migrateOperations: [string, MigrateOperation][]
} {
return { ...prepareToolsRaw(builder.getTxes()), version, migrateOperations }
const enabled = (process.env.MODEL_ENABLED ?? '*').split(',').map((it) => it.trim())
const disabled = (process.env.MODEL_DISABLED ?? '').split(',').map((it) => it.trim())
return { ...prepareToolsRaw(builder(enabled, disabled).getTxes()), version, migrateOperations }
}
devTool(prepareTools, '')

View File

@ -29,7 +29,7 @@ export async function cleanWorkspace (
minio: MinioService,
elasticUrl: string,
transactorUrl: string,
opt: { recruit: boolean, tracker: boolean, removeTx: boolean }
opt: { recruit: boolean, tracker: boolean, removedTx: boolean }
): Promise<void> {
const connection = (await connect(transactorUrl, workspaceId, undefined, {
mode: 'backup',
@ -106,7 +106,7 @@ export async function cleanWorkspace (
await client.connect()
const db = getWorkspaceDB(client, workspaceId)
if (opt.removeTx) {
if (opt.removedTx) {
const txes = await db.collection(DOMAIN_TX).find({}).toArray()
for (const tx of txes) {

View File

@ -0,0 +1,70 @@
//
// 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.
//
import core, { BackupClient, Client as CoreClient, TxFactory, WorkspaceId } from '@hcengineering/core'
import { connect } from '@hcengineering/server-tool'
function toLen (val: string, sep: string, len: number): string {
while (val.length < len) {
val += sep
}
return val
}
export async function changeConfiguration (
workspaceId: WorkspaceId,
transactorUrl: string,
cmd: { enable?: string, disable?: string, list?: boolean }
): Promise<void> {
const connection = (await connect(transactorUrl, workspaceId, undefined, {
mode: 'backup'
})) as unknown as CoreClient & BackupClient
try {
const config = await connection.findAll(core.class.PluginConfiguration, {})
if (cmd.list === true) {
for (const c of config) {
if (c.label !== undefined) {
console.log(toLen(c.pluginId, '-', 20), c.enabled)
}
}
}
const enable = (cmd.enable ?? '').trim().split(',')
console.log('enable', enable)
const ops = new TxFactory(core.account.ConfigUser)
if (enable.length > 0) {
const p = config.filter((it) => enable.includes(it.pluginId) || enable.includes('*'))
for (const pp of p) {
if (!pp.enabled) {
console.log('Enabling', pp.pluginId)
await connection.tx(
ops.createTxUpdateDoc(core.class.PluginConfiguration, core.space.Model, pp._id, { enabled: true })
)
}
}
}
if ((cmd.disable ?? '').trim() !== '') {
const p = config.find((it) => it.pluginId === (cmd.disable ?? '').trim())
if (p !== undefined) {
await connection.tx(
ops.createTxUpdateDoc(core.class.PluginConfiguration, core.space.Model, p._id, { enabled: false })
)
}
}
} catch (err: any) {
console.trace(err)
} finally {
await connection.close()
}
}

View File

@ -52,6 +52,7 @@ import { openAIConfigDefaults } from '@hcengineering/openai'
import { cleanArchivedSpaces, cleanRemovedTransactions, cleanWorkspace } from './clean'
import { rebuildElastic } from './elastic'
import { openAIConfig } from './openai'
import { changeConfiguration } from './configuration'
/**
* @public
@ -442,7 +443,7 @@ export function devTool (
.option('--recruit', 'Clean recruit', false)
.option('--tracker', 'Clean tracker', false)
.option('--removedTx', 'Clean removed transactions', false)
.action(async (workspace: string, cmd: { recruit: boolean, tracker: boolean, removeTx: boolean }) => {
.action(async (workspace: string, cmd: { recruit: boolean, tracker: boolean, removedTx: boolean }) => {
const { mongodbUri, minio } = prepareTools()
return await withDatabase(mongodbUri, async (db) => {
await cleanWorkspace(
@ -470,5 +471,16 @@ export function devTool (
await cleanArchivedSpaces(getWorkspaceId(workspace, productId), transactorUrl)
})
program
.command('configure <workspace>')
.description('clean archived spaces')
.option('--enable <enable>', 'Enable plugin configuration', '')
.option('--disable <disable>', 'Disable plugin configuration', '')
.option('--list', 'List plugin states', false)
.action(async (workspace: string, cmd: { enable: string, disable: string, list: boolean }) => {
console.log(JSON.stringify(cmd))
await changeConfiguration(getWorkspaceId(workspace, productId), transactorUrl, cmd)
})
program.parse(process.argv)
}

View File

@ -21,6 +21,8 @@ import { TClass, TDoc } from '@hcengineering/model-core'
import type { Asset, IntlString, Resource } from '@hcengineering/platform'
import { AnyComponent } from '@hcengineering/ui'
export { activityId } from '@hcengineering/activity'
@Model(activity.class.TxViewlet, core.class.Doc, DOMAIN_MODEL)
export class TTxViewlet extends TDoc implements TxViewlet {
icon!: Asset

View File

@ -64,6 +64,7 @@
"@hcengineering/model-notification": "^0.6.0",
"@hcengineering/model-text-editor": "^0.6.0",
"@hcengineering/core": "^0.6.23",
"@hcengineering/platform": "^0.6.8",
"@hcengineering/model-tags": "^0.6.0",
"@hcengineering/model-calendar": "^0.6.0",
"@hcengineering/model-server-calendar": "^0.6.0",

View File

@ -16,7 +16,7 @@
import builder from '.'
// import { writeFileSync } from 'fs'
const content = JSON.stringify(builder.getTxes(), undefined, 2)
const content = JSON.stringify(builder().getTxes(), undefined, 2)
console.log(content)
// writeFileSync('../../dev/storage/src/model.tx.json', content)
// writeFileSync('../../server/workspace/src/model.tx.json', content)

View File

@ -17,132 +17,310 @@ import core, { coreId, Data, PluginConfiguration, Ref, Tx, Version } from '@hcen
import jsonVersion from './version.json'
import { Builder } from '@hcengineering/model'
import { createModel as activityModel } from '@hcengineering/model-activity'
import { createModel as attachmentModel } from '@hcengineering/model-attachment'
import { createModel as automationModel } from '@hcengineering/model-automation'
import { createModel as chunterModel } from '@hcengineering/model-chunter'
import { createModel as contactModel } from '@hcengineering/model-contact'
import { activityId, createModel as activityModel } from '@hcengineering/model-activity'
import { attachmentId, createModel as attachmentModel } from '@hcengineering/model-attachment'
import { automationId, createModel as automationModel } from '@hcengineering/model-automation'
import bitrix, { bitrixId, createModel as bitrixModel } from '@hcengineering/model-bitrix'
import board, { boardId, createModel as boardModel } from '@hcengineering/model-board'
import calendar, { calendarId, createModel as calendarModel } from '@hcengineering/model-calendar'
import chunter, { chunterId, createModel as chunterModel } from '@hcengineering/model-chunter'
import contact, { contactId, createModel as contactModel } from '@hcengineering/model-contact'
import { createModel as coreModel } from '@hcengineering/model-core'
import { createModel as gmailModel } from '@hcengineering/model-gmail'
import { createModel as inventoryModel } from '@hcengineering/model-inventory'
import { createModel as leadModel } from '@hcengineering/model-lead'
import { createModel as presentationModel } from '@hcengineering/model-presentation'
import { createModel as recruitModel } from '@hcengineering/model-recruit'
import { createModel as serverAttachmentModel } from '@hcengineering/model-server-attachment'
import { createModel as serverContactModel } from '@hcengineering/model-server-contact'
import { createModel as serverNotificationModel } from '@hcengineering/model-server-notification'
import { createModel as serverChunterModel } from '@hcengineering/model-server-chunter'
import { createModel as serverInventoryModel } from '@hcengineering/model-server-inventory'
import { createModel as serverLeadModel } from '@hcengineering/model-server-lead'
import { createModel as serverTaskModel } from '@hcengineering/model-server-task'
import { createModel as serverTrackerModel } from '@hcengineering/model-server-tracker'
import { createModel as serverTagsModel } from '@hcengineering/model-server-tags'
import { createModel as serveSettingModel } from '@hcengineering/model-server-setting'
import { createModel as serverRecruitModel } from '@hcengineering/model-server-recruit'
import { createModel as serverCoreModel } from '@hcengineering/model-server-core'
import { createModel as settingModel } from '@hcengineering/model-setting'
import { createModel as taskModel } from '@hcengineering/model-task'
import { createModel as telegramModel } from '@hcengineering/model-telegram'
import { createModel as templatesModel } from '@hcengineering/model-templates'
import { createModel as textEditorModel } from '@hcengineering/model-text-editor'
import { createModel as viewModel } from '@hcengineering/model-view'
import { createModel as workbenchModel } from '@hcengineering/model-workbench'
import { createModel as notificationModel } from '@hcengineering/model-notification'
import { createModel as tagsModel } from '@hcengineering/model-tags'
import { createModel as calendarModel } from '@hcengineering/model-calendar'
import { createModel as serverCalendarModel } from '@hcengineering/model-server-calendar'
import { createModel as serverGmailModel } from '@hcengineering/model-server-gmail'
import { createModel as serverTelegramModel } from '@hcengineering/model-server-telegram'
import { createModel as trackerModel } from '@hcengineering/model-tracker'
import { createModel as boardModel } from '@hcengineering/model-board'
import { createModel as preferenceModel } from '@hcengineering/model-preference'
import { createModel as hrModel } from '@hcengineering/model-hr'
import { createModel as serverHrModel } from '@hcengineering/model-server-hr'
import { createModel as documentModel } from '@hcengineering/model-document'
import { createModel as bitrixModel } from '@hcengineering/model-bitrix'
import { createModel as requestModel } from '@hcengineering/model-request'
import { createModel as serverRequestModel } from '@hcengineering/model-server-request'
import { createModel as serverViewModel } from '@hcengineering/model-server-view'
import document, { documentId, createModel as documentModel } from '@hcengineering/model-document'
import gmail, { gmailId, createModel as gmailModel } from '@hcengineering/model-gmail'
import hr, { hrId, createModel as hrModel } from '@hcengineering/model-hr'
import inventory, { inventoryId, createModel as inventoryModel } from '@hcengineering/model-inventory'
import lead, { leadId, createModel as leadModel } from '@hcengineering/model-lead'
import { notificationId, createModel as notificationModel } from '@hcengineering/model-notification'
import { preferenceId, createModel as preferenceModel } from '@hcengineering/model-preference'
import { presentationId, createModel as presentationModel } from '@hcengineering/model-presentation'
import recruit, { recruitId, createModel as recruitModel } from '@hcengineering/model-recruit'
import { requestId, createModel as requestModel } from '@hcengineering/model-request'
import { serverAttachmentId, createModel as serverAttachmentModel } from '@hcengineering/model-server-attachment'
import { serverCalendarId, createModel as serverCalendarModel } from '@hcengineering/model-server-calendar'
import { serverChunterId, createModel as serverChunterModel } from '@hcengineering/model-server-chunter'
import { serverContactId, createModel as serverContactModel } from '@hcengineering/model-server-contact'
import { serverCoreId, createModel as serverCoreModel } from '@hcengineering/model-server-core'
import { serverGmailId, createModel as serverGmailModel } from '@hcengineering/model-server-gmail'
import { serverHrId, createModel as serverHrModel } from '@hcengineering/model-server-hr'
import { serverInventoryId, createModel as serverInventoryModel } from '@hcengineering/model-server-inventory'
import { serverLeadId, createModel as serverLeadModel } from '@hcengineering/model-server-lead'
import { serverNotificationId, createModel as serverNotificationModel } from '@hcengineering/model-server-notification'
import { serverRecruitId, createModel as serverRecruitModel } from '@hcengineering/model-server-recruit'
import { serverRequestId, createModel as serverRequestModel } from '@hcengineering/model-server-request'
import { serverSettingId, createModel as serveSettingModel } from '@hcengineering/model-server-setting'
import { serverTagsId, createModel as serverTagsModel } from '@hcengineering/model-server-tags'
import { serverTaskId, createModel as serverTaskModel } from '@hcengineering/model-server-task'
import { serverTelegramId, createModel as serverTelegramModel } from '@hcengineering/model-server-telegram'
import { serverTrackerId, createModel as serverTrackerModel } from '@hcengineering/model-server-tracker'
import { serverViewId, createModel as serverViewModel } from '@hcengineering/model-server-view'
import setting, { settingId, createModel as settingModel } from '@hcengineering/model-setting'
import { tagsId, createModel as tagsModel } from '@hcengineering/model-tags'
import { taskId, createModel as taskModel } from '@hcengineering/model-task'
import telegram, { telegramId, createModel as telegramModel } from '@hcengineering/model-telegram'
import { templatesId, createModel as templatesModel } from '@hcengineering/model-templates'
import { textEditorId, createModel as textEditorModel } from '@hcengineering/model-text-editor'
import tracker, { trackerId, createModel as trackerModel } from '@hcengineering/model-tracker'
import view, { viewId, createModel as viewModel } from '@hcengineering/model-view'
import workbench, { workbenchId, createModel as workbenchModel } from '@hcengineering/model-workbench'
import { createModel as serverTranslate } from '@hcengineering/model-server-translate'
import { createModel as serverOpenAI } from '@hcengineering/model-server-openai'
import { openAIId, createModel as serverOpenAI } from '@hcengineering/model-server-openai'
import { createModel as serverTranslate, translateId } from '@hcengineering/model-server-translate'
import { Plugin } from '@hcengineering/platform'
export const version: Data<Version> = jsonVersion as Data<Version>
const builder = new Builder()
interface ConfigurablePlugin extends Omit<Data<PluginConfiguration>, 'pluginId' | 'transactions'> {}
const builders: [(b: Builder) => void, string][] = [
[coreModel, coreId],
[activityModel, 'activity'],
[attachmentModel, 'attachment'],
[tagsModel, 'tags'],
[viewModel, 'view'],
[workbenchModel, 'workbench'],
[contactModel, 'contact'],
[chunterModel, 'chunter'],
[taskModel, 'task'],
[recruitModel, 'recruit'],
[settingModel, 'setting'],
[telegramModel, 'telegram'],
[leadModel, 'lead'],
[gmailModel, 'gmail'],
[inventoryModel, 'inventory'],
[presentationModel, 'presentation'],
[templatesModel, 'templates'],
[textEditorModel, 'text-editor'],
[notificationModel, 'notification'],
[preferenceModel, 'preference'],
[hrModel, 'hr'],
[documentModel, 'document'],
[trackerModel, 'tracker'],
[boardModel, 'board'],
[calendarModel, 'calendar'],
[bitrixModel, 'bitrix'],
[requestModel, 'request'],
type BuilderConfig = [(b: Builder) => void, Plugin] | [(b: Builder) => void, Plugin, ConfigurablePlugin | undefined]
[serverCoreModel, 'server-core'],
[serverAttachmentModel, 'server-attachment'],
[serverContactModel, 'server-contact'],
[serveSettingModel, 'server-setting'],
[serverChunterModel, 'server-chunter'],
[serverInventoryModel, 'server-inventory'],
[serverLeadModel, 'server-lead'],
[serverTagsModel, 'server-tags'],
[serverTaskModel, 'server-task'],
[serverTrackerModel, 'server-tracker'],
[serverRecruitModel, 'server-recruit'],
[serverCalendarModel, 'server-calendar'],
[serverGmailModel, 'server-gmail'],
[serverTelegramModel, 'server-telegram'],
[serverHrModel, 'server-hr'],
[serverNotificationModel, 'server-notification'],
[serverRequestModel, 'server-request'],
[serverViewModel, 'server-view'],
[automationModel, 'automation'],
[serverTranslate, 'translate'],
[serverOpenAI, 'openai']
]
/**
* @public
* @param enabled - a set of enabled plugins
* @param disabled - a set of disabled plugins
* @returns
*/
export default function buildModel (enabled: string[] = ['*'], disabled: string[] = []): Builder {
const builder = new Builder()
for (const [b, id] of builders) {
const txes: Tx[] = []
builder.onTx = (tx) => {
txes.push(tx)
const builders: BuilderConfig[] = [
[coreModel, coreId],
[activityModel, activityId],
[attachmentModel, attachmentId],
[tagsModel, tagsId],
[viewModel, viewId],
[workbenchModel, workbenchId],
[
contactModel,
contactId,
{
label: contact.string.ConfigLabel,
description: contact.string.ConfigDescription,
enabled: true,
configurable: false,
icon: contact.icon.ContactApplication,
classFilter: [workbench.class.Application]
}
],
[
chunterModel,
chunterId,
{
label: chunter.string.ConfigLabel,
description: chunter.string.ConfigDescription,
enabled: false,
configurable: false,
icon: chunter.icon.Chunter,
classFilter: [workbench.class.Application]
}
],
[taskModel, taskId],
[
recruitModel,
recruitId,
{
label: recruit.string.ConfigLabel,
description: recruit.string.ConfigDescription,
enabled: true,
icon: recruit.icon.RecruitApplication,
classFilter: [workbench.class.Application, view.class.Action],
configurable: true
}
],
[settingModel, settingId],
[
telegramModel,
telegramId,
{
label: telegram.string.ConfigLabel,
description: telegram.string.ConfigDescription,
enabled: true,
classFilter: [
workbench.class.Application,
view.class.Action,
contact.class.ChannelProvider,
setting.class.IntegrationType
],
configurable: true
}
],
[
leadModel,
leadId,
{
label: lead.string.ConfigLabel,
description: lead.string.ConfigDescription,
enabled: true,
icon: lead.icon.LeadApplication,
configurable: false
}
],
[
gmailModel,
gmailId,
{
label: gmail.string.ConfigLabel,
description: gmail.string.ConfigDescription,
enabled: true,
classFilter: [
workbench.class.Application,
view.class.Action,
contact.class.ChannelProvider,
setting.class.IntegrationType
],
configurable: true
}
],
[
inventoryModel,
inventoryId,
{
label: inventory.string.ConfigLabel,
description: inventory.string.ConfigDescription,
enabled: true,
icon: inventory.icon.InventoryApplication,
classFilter: [workbench.class.Application, view.class.Action],
configurable: false
}
],
[presentationModel, presentationId],
[templatesModel, templatesId],
[textEditorModel, textEditorId],
[notificationModel, notificationId],
[preferenceModel, preferenceId],
[
hrModel,
hrId,
{
label: hr.string.ConfigLabel,
description: hr.string.ConfigDescription,
enabled: true,
icon: hr.icon.Structure,
classFilter: [workbench.class.Application, view.class.Action],
configurable: true
}
],
[
documentModel,
documentId,
{
label: document.string.ConfigLabel,
description: document.string.ConfigDescription,
enabled: true,
icon: document.icon.DocumentApplication,
configurable: false
}
],
[
trackerModel,
trackerId,
{
label: tracker.string.ConfigLabel,
description: tracker.string.ConfigDescription,
enabled: true,
icon: tracker.icon.TrackerApplication,
classFilter: [workbench.class.Application, view.class.Action],
configurable: true
}
],
[
boardModel,
boardId,
{
label: board.string.ConfigLabel,
description: board.string.ConfigDescription,
enabled: true,
icon: board.icon.Board,
classFilter: [workbench.class.Application, view.class.Action],
configurable: false
}
],
[
calendarModel,
calendarId,
{
label: calendar.string.ConfigLabel,
description: calendar.string.ConfigDescription,
enabled: true,
icon: calendar.icon.Calendar,
classFilter: [workbench.class.Application],
configurable: false
}
],
[
bitrixModel,
bitrixId,
{
label: bitrix.string.ConfigLabel,
description: bitrix.string.ConfigDescription,
enabled: false,
icon: bitrix.icon.Bitrix,
configurable: false
}
],
[
requestModel,
requestId,
{
// label: request.string.ConfigLabel,
// description: request.string.ConfigDescription,
enabled: false,
configurable: false,
classFilter: [workbench.class.Application, view.class.Action]
}
],
[automationModel, automationId],
[serverCoreModel, serverCoreId],
[serverAttachmentModel, serverAttachmentId],
[serverContactModel, serverContactId],
[serveSettingModel, serverSettingId],
[serverChunterModel, serverChunterId],
[serverInventoryModel, serverInventoryId],
[serverLeadModel, serverLeadId],
[serverTagsModel, serverTagsId],
[serverTaskModel, serverTaskId],
[serverTrackerModel, serverTrackerId],
[serverRecruitModel, serverRecruitId],
[serverCalendarModel, serverCalendarId],
[serverGmailModel, serverGmailId],
[serverTelegramModel, serverTelegramId],
[serverHrModel, serverHrId],
[serverNotificationModel, serverNotificationId],
[serverRequestModel, serverRequestId],
[serverViewModel, serverViewId],
[serverTranslate, translateId],
[serverOpenAI, openAIId]
]
for (const [b, id, config] of builders) {
const txes: Tx[] = []
builder.onTx = (tx) => {
txes.push(tx)
}
b(builder)
builder.createDoc(
core.class.PluginConfiguration,
core.space.Model,
{
pluginId: id,
transactions: txes.map((it) => it._id),
...config,
enabled:
config?.label === undefined ||
((config?.enabled ?? true) && (enabled.includes(id) || enabled.includes('*')) && !disabled.includes(id)),
configurable: config?.configurable ?? false
},
('plugin-configuration-' + id) as Ref<PluginConfiguration>
)
builder.onTx = undefined
}
b(builder)
builder.createDoc(
core.class.PluginConfiguration,
core.space.Model,
{
pluginId: id,
transactions: txes.map((it) => it._id)
},
('plugin-configuration-' + id) as Ref<PluginConfiguration>
)
builder.onTx = undefined
}
builder.createDoc(core.class.Version, core.space.Model, version, core.version.Model)
export default builder
builder.createDoc(core.class.Version, core.space.Model, version, core.version.Model)
return builder
}
// Export upgrade procedures
export { migrateOperations } from './migration'

View File

@ -33,6 +33,7 @@ import preference, { TPreference } from '@hcengineering/model-preference'
import view, { createAction } from '@hcengineering/model-view'
import attachment from './plugin'
export { attachmentId } from '@hcengineering/attachment'
export { attachmentOperation } from './migration'
export const DOMAIN_ATTACHMENT = 'attachment' as Domain

View File

@ -15,10 +15,10 @@
// To help typescript locate view plugin properly
import automation, {
Automation,
AutomationSupport,
AttributeAutomationSupport,
Automation,
AutomationSortSupport,
AutomationSupport,
AutomationTriggerSupport,
Command,
TriggerType
@ -28,6 +28,9 @@ import { Builder, Mixin, Model, Prop, TypeString, UX } from '@hcengineering/mode
import core, { TAttachedDoc, TClass } from '@hcengineering/model-core'
import view from '@hcengineering/view'
export { automationId } from '@hcengineering/automation'
export { automationOperation } from './migration'
export const DOMAIN_AUTOMATION = 'automation' as Domain
@Model(automation.class.Automation, core.class.AttachedDoc, DOMAIN_AUTOMATION)
@ -90,5 +93,3 @@ export function createModel (builder: Builder): void {
actions: [view.action.Delete]
})
}
export { automationOperation } from './migration'

View File

@ -26,6 +26,10 @@ import view, { createAction } from '@hcengineering/model-view'
import { getEmbeddedLabel } from '@hcengineering/platform'
import setting from '@hcengineering/setting'
export { bitrixId } from '@hcengineering/bitrix'
export { bitrixOperation } from './migration'
export { default } from './plugin'
const DOMAIN_BITRIX = 'bitrix' as Domain
@Mixin(bitrix.mixin.BitrixSyncDoc, core.class.Doc)
@ -103,5 +107,3 @@ export function createModel (builder: Builder): void {
bitrix.action.BitrixImport
)
}
export { bitrixOperation } from './migration'

View File

@ -29,7 +29,9 @@ export default mergeIds(bitrixId, bitrix, {
BitrixImport: '' as AnyComponent
},
string: {
BitrixImport: '' as IntlString
BitrixImport: '' as IntlString,
ConfigLabel: '' as IntlString,
ConfigDescription: '' as IntlString
},
action: {
BitrixImport: '' as Ref<Action>

View File

@ -44,6 +44,10 @@ import { IntlString } from '@hcengineering/platform'
import type { AnyComponent } from '@hcengineering/ui'
import board from './plugin'
export { boardId } from '@hcengineering/board'
export { boardOperation } from './migration'
export { default } from './plugin'
@Model(board.class.Board, task.class.SpaceWithStates)
@UX(board.string.Board, board.icon.Board)
export class TBoard extends TSpaceWithStates implements Board {
@ -542,6 +546,3 @@ export function createModel (builder: Builder): void {
}
})
}
export { boardOperation } from './migration'
export { default } from './plugin'

View File

@ -58,7 +58,9 @@ export default mergeIds(boardId, board, {
},
string: {
CommonBoardPreference: '' as IntlString,
ConvertToCard: '' as IntlString
ConvertToCard: '' as IntlString,
ConfigLabel: '' as IntlString,
ConfigDescription: '' as IntlString
},
action: {
ConvertToCard: '' as Ref<Action>

View File

@ -14,9 +14,9 @@
//
import activity from '@hcengineering/activity'
import { calendarId, Calendar, Event, Reminder } from '@hcengineering/calendar'
import { Calendar, Event, Reminder, calendarId } from '@hcengineering/calendar'
import { Employee } from '@hcengineering/contact'
import { DateRangeMode, Domain, Markup, Ref, Timestamp, IndexKind } from '@hcengineering/core'
import { DateRangeMode, Domain, IndexKind, Markup, Ref, Timestamp } from '@hcengineering/core'
import {
ArrOf,
Builder,
@ -43,6 +43,8 @@ import notification from '@hcengineering/notification'
import calendar from './plugin'
export * from '@hcengineering/calendar'
export { calendarId } from '@hcengineering/calendar'
export { calendarOperation } from './migration'
export const DOMAIN_CALENDAR = 'calendar' as Domain
@ -200,5 +202,4 @@ export function createModel (builder: Builder): void {
})
}
export { calendarOperation } from './migration'
export default calendar

View File

@ -45,7 +45,9 @@ export default mergeIds(calendarId, calendar, {
Reminder: '' as IntlString,
Shift: '' as IntlString,
State: '' as IntlString,
CreatedReminder: '' as IntlString
CreatedReminder: '' as IntlString,
ConfigLabel: '' as IntlString,
ConfigDescription: '' as IntlString
},
viewlet: {
Calendar: '' as Ref<ViewletDescriptor>,

View File

@ -48,9 +48,11 @@ import attachment from '@hcengineering/model-attachment'
import core, { TAttachedDoc, TSpace } from '@hcengineering/model-core'
import notification from '@hcengineering/model-notification'
import preference, { TPreference } from '@hcengineering/model-preference'
import view, { actionTemplates as viewTemplates, createAction } from '@hcengineering/model-view'
import view, { createAction, actionTemplates as viewTemplates } from '@hcengineering/model-view'
import workbench from '@hcengineering/model-workbench'
import chunter from './plugin'
export { chunterId } from '@hcengineering/chunter'
export { chunterOperation } from './migration'
export const DOMAIN_CHUNTER = 'chunter' as Domain
export const DOMAIN_COMMENT = 'comment' as Domain
@ -653,6 +655,4 @@ export function createModel (builder: Builder, options = { addApplication: true
})
}
export { chunterOperation } from './migration'
export default chunter

View File

@ -74,7 +74,9 @@ export default mergeIds(chunterId, chunter, {
Reactions: '' as IntlString,
Emoji: '' as IntlString,
FilterComments: '' as IntlString,
FilterBacklinks: '' as IntlString
FilterBacklinks: '' as IntlString,
ConfigLabel: '' as IntlString,
ConfigDescription: '' as IntlString
},
viewlet: {
Chat: '' as Ref<ViewletDescriptor>

View File

@ -60,6 +60,10 @@ import templates from '@hcengineering/templates'
import { AnyComponent } from '@hcengineering/ui'
import contact from './plugin'
export { contactId } from '@hcengineering/contact'
export { contactOperation } from './migration'
export { contact as default }
export const DOMAIN_CONTACT = 'contact' as Domain
export const DOMAIN_CHANNEL = 'channel' as Domain
@ -767,6 +771,3 @@ export function createModel (builder: Builder): void {
component: contact.component.ActivityChannelMessage
})
}
export { contactOperation } from './migration'
export { contact as default }

View File

@ -82,7 +82,11 @@ export default mergeIds(contactId, contact, {
WhatsappPlaceholder: '' as IntlString,
Profile: '' as IntlString,
ProfilePlaceholder: '' as IntlString,
CurrentEmployee: '' as IntlString
CurrentEmployee: '' as IntlString,
ConfigLabel: '' as IntlString,
ConfigDescription: '' as IntlString
},
completion: {
PersonQuery: '' as Resource<ObjectSearchFactory>,

View File

@ -65,7 +65,7 @@ import {
TypeTimestamp,
UX
} from '@hcengineering/model'
import { getEmbeddedLabel, IntlString } from '@hcengineering/platform'
import { getEmbeddedLabel, IntlString, Plugin } from '@hcengineering/platform'
import core from './component'
// C O R E
@ -237,8 +237,12 @@ export class TVersion extends TDoc implements Version {
@Model(core.class.PluginConfiguration, core.class.Doc, DOMAIN_MODEL)
export class TPluginConfiguration extends TDoc implements PluginConfiguration {
pluginId!: string
pluginId!: Plugin
transactions!: Ref<Doc>[]
label!: IntlString
enabled!: boolean
configurable!: boolean
}
@Model(core.class.BlobData, core.class.Doc, DOMAIN_BLOB)

View File

@ -15,13 +15,13 @@
import {
AccountRole,
TxCollectionCUD,
Doc,
AttachedDoc,
IndexingConfiguration,
Class,
systemAccountEmail,
DocIndexState
Doc,
DocIndexState,
IndexingConfiguration,
TxCollectionCUD,
systemAccountEmail
} from '@hcengineering/core'
import { Builder } from '@hcengineering/model'
import core from './component'
@ -38,8 +38,8 @@ import {
TDocIndexState,
TEnum,
TEnumOf,
TFulltextData,
TFullTextSearchContext,
TFulltextData,
TIndexConfiguration,
TIndexStageState,
TInterface,
@ -63,13 +63,14 @@ import {
import { TAccount, TSpace } from './security'
import { TStatus, TStatusCategory } from './status'
import { TUserStatus } from './transient'
import { TTx, TTxApplyIf, TTxCollectionCUD, TTxCreateDoc, TTxCUD, TTxMixin, TTxRemoveDoc, TTxUpdateDoc } from './tx'
import { TTx, TTxApplyIf, TTxCUD, TTxCollectionCUD, TTxCreateDoc, TTxMixin, TTxRemoveDoc, TTxUpdateDoc } from './tx'
export { coreId } from '@hcengineering/core'
export * from './core'
export { coreOperation } from './migration'
export * from './security'
export * from './tx'
export * from './status'
export * from './tx'
export { core as default }
export function createModel (builder: Builder): void {

View File

@ -82,7 +82,7 @@ export const demoOperation: MigrateOperation = {
email: 'rosamund@hc.engineering',
employee,
name: 'Chen,Rosamund',
role: AccountRole.Owner
role: AccountRole.User
})
}

View File

@ -19,11 +19,11 @@ import { IndexKind } from '@hcengineering/core'
import {
CollaboratorDocument,
Document,
documentId,
DocumentRequest,
DocumentRequestKind,
DocumentVersion,
DocumentVersionState
DocumentVersionState,
documentId
} from '@hcengineering/document'
import {
ArrOf,
@ -45,10 +45,14 @@ import core, { TAttachedDoc, TDoc } from '@hcengineering/model-core'
import presentation from '@hcengineering/model-presentation'
import view, { actionTemplates, createAction } from '@hcengineering/model-view'
import workbench from '@hcengineering/model-workbench'
import tags from '@hcengineering/tags'
import notification from '@hcengineering/notification'
import tags from '@hcengineering/tags'
import document from './plugin'
export { documentId } from '@hcengineering/document'
export { documentOperation } from './migration'
export { document as default }
export const DOMAIN_DOCUMENT = 'document' as Domain
@Model(document.class.DocumentRequest, core.class.AttachedDoc, DOMAIN_DOCUMENT)
@ -266,6 +270,3 @@ export function createModel (builder: Builder): void {
editor: document.component.DocumentVersions
})
}
export { documentOperation } from './migration'
export { document as default }

View File

@ -18,7 +18,7 @@ import {} from '@hcengineering/core'
import { documentId } from '@hcengineering/document'
import document from '@hcengineering/document-resources/src/plugin'
import { ObjectSearchCategory, ObjectSearchFactory } from '@hcengineering/model-presentation'
import { mergeIds, Resource } from '@hcengineering/platform'
import { IntlString, mergeIds, Resource } from '@hcengineering/platform'
import { TagCategory } from '@hcengineering/tags'
import { AnyComponent } from '@hcengineering/ui'
import { ActionCategory } from '@hcengineering/view'
@ -40,5 +40,9 @@ export default mergeIds(documentId, document, {
},
viewlet: {
TableDocument: '' as Ref<Doc>
},
string: {
ConfigLabel: '' as IntlString,
ConfigDescription: '' as IntlString
}
})

View File

@ -35,6 +35,10 @@ import view, { createAction } from '@hcengineering/model-view'
import setting from '@hcengineering/setting'
import gmail from './plugin'
export { gmailId } from '@hcengineering/gmail'
export { gmailOperation } from './migration'
export { default } from './plugin'
export const DOMAIN_GMAIL = 'gmail' as Domain
function TypeSharedMessage (): Type<SharedMessage> {
@ -213,5 +217,3 @@ export function createModel (builder: Builder): void {
parentPropagate: false
})
}
export { gmailOperation } from './migration'

View File

@ -37,7 +37,9 @@ export default mergeIds(gmailId, gmail, {
Messages: '' as IntlString,
Incoming: '' as IntlString,
Status: '' as IntlString,
EmailPlaceholder: '' as IntlString
EmailPlaceholder: '' as IntlString,
ConfigLabel: '' as IntlString,
ConfigDescription: '' as IntlString
},
ids: {
TxSharedCreate: '' as Ref<TxViewlet>

View File

@ -14,16 +14,16 @@
//
import { Contact, Employee } from '@hcengineering/contact'
import { Arr, Class, Domain, DOMAIN_MODEL, IndexKind, Markup, Ref, Type } from '@hcengineering/core'
import { Arr, Class, DOMAIN_MODEL, Domain, IndexKind, Markup, Ref, Type } from '@hcengineering/core'
import {
Department,
DepartmentMember,
hrId,
PublicHoliday,
Request,
RequestType,
Staff,
TzDate
TzDate,
hrId
} from '@hcengineering/hr'
import {
ArrOf,
@ -47,9 +47,13 @@ import contact, { TEmployee, TEmployeeAccount } from '@hcengineering/model-conta
import core, { TAttachedDoc, TDoc, TSpace, TType } from '@hcengineering/model-core'
import view, { classPresenter, createAction } from '@hcengineering/model-view'
import workbench from '@hcengineering/model-workbench'
import notification from '@hcengineering/notification'
import { Asset, IntlString } from '@hcengineering/platform'
import hr from './plugin'
import notification from '@hcengineering/notification'
export { hrId } from '@hcengineering/hr'
export { hrOperation } from './migration'
export { default } from './plugin'
export const DOMAIN_HR = 'hr' as Domain
@ -482,6 +486,3 @@ export function createModel (builder: Builder): void {
hr.ids.CreatePublicHolidayNotification
)
}
export { hrOperation } from './migration'
export { default } from './plugin'

View File

@ -33,7 +33,9 @@ export default mergeIds(hrId, hr, {
Overtime: '' as IntlString,
Overtime2: '' as IntlString,
Subscribers: '' as IntlString,
PublicHoliday: '' as IntlString
PublicHoliday: '' as IntlString,
ConfigLabel: '' as IntlString,
ConfigDescription: '' as IntlString
},
component: {
Structure: '' as AnyComponent,

View File

@ -14,7 +14,7 @@
//
import { Domain, IndexKind, Ref } from '@hcengineering/core'
import { Category, inventoryId, Product, Variant } from '@hcengineering/inventory'
import { Category, Product, Variant, inventoryId } from '@hcengineering/inventory'
import { Builder, Collection, Index, Model, Prop, TypeRef, TypeString, UX } from '@hcengineering/model'
import attachment from '@hcengineering/model-attachment'
import core, { TAttachedDoc } from '@hcengineering/model-core'
@ -25,6 +25,10 @@ import setting from '@hcengineering/setting'
import view, { Viewlet } from '@hcengineering/view'
import inventory from './plugin'
export { inventoryId } from '@hcengineering/inventory'
export { inventoryOperation } from './migration'
export { default } from './plugin'
export const DOMAIN_INVENTORY = 'inventory' as Domain
@Model(inventory.class.Category, core.class.AttachedDoc, DOMAIN_INVENTORY)
@UX(inventory.string.Category, inventory.icon.Categories, undefined, 'name')
@ -175,6 +179,3 @@ export function createModel (builder: Builder): void {
filters: ['attachedTo']
})
}
export { inventoryOperation } from './migration'
export { default } from './plugin'

View File

@ -17,7 +17,7 @@
import type { Ref } from '@hcengineering/core'
import { inventoryId } from '@hcengineering/inventory'
import inventory from '@hcengineering/inventory-resources/src/plugin'
import { mergeIds } from '@hcengineering/platform'
import { IntlString, mergeIds } from '@hcengineering/platform'
import type { AnyComponent } from '@hcengineering/ui'
import { Action, ActionCategory, ViewAction, Viewlet } from '@hcengineering/view'
@ -43,5 +43,9 @@ export default mergeIds(inventoryId, inventory, {
},
viewlet: {
TableProduct: '' as Ref<Viewlet>
},
string: {
ConfigLabel: '' as IntlString,
ConfigDescription: '' as IntlString
}
})

View File

@ -40,6 +40,10 @@ import setting from '@hcengineering/setting'
import { ViewOptionsModel } from '@hcengineering/view'
import lead from './plugin'
export { leadId } from '@hcengineering/lead'
export { leadOperation } from './migration'
export { default } from './plugin'
@Model(lead.class.Funnel, task.class.SpaceWithStates)
@UX(lead.string.Funnel, lead.icon.Funnel)
export class TFunnel extends TSpaceWithStates implements Funnel {
@ -419,6 +423,3 @@ export function createModel (builder: Builder): void {
lead.action.CreateGlobalLead
)
}
export { leadOperation } from './migration'
export { default } from './plugin'

View File

@ -32,7 +32,9 @@ export default mergeIds(leadId, lead, {
Title: '' as IntlString,
ManageFunnelStatuses: '' as IntlString,
FunnelBrowser: '' as IntlString,
GotoLeadApplication: '' as IntlString
GotoLeadApplication: '' as IntlString,
ConfigLabel: '' as IntlString,
ConfigDescription: '' as IntlString
},
component: {
CreateLead: '' as AnyComponent,

View File

@ -8,6 +8,7 @@
"resolveJsonModule": true,
"experimentalDecorators": true,
"skipLibCheck": true,
"incremental": true
"incremental": true,
"declarationMap": true
}
}

View File

@ -17,6 +17,7 @@
import { Account, Class, Doc, Domain, DOMAIN_MODEL, IndexKind, Ref, Timestamp, TxCUD } from '@hcengineering/core'
import { ArrOf, Builder, Index, Mixin, Model, Prop, TypeRef, TypeString, UX } from '@hcengineering/model'
import core, { TAttachedDoc, TClass, TDoc } from '@hcengineering/model-core'
import view, { createAction } from '@hcengineering/model-view'
import {
AnotherUserNotifications,
DocUpdates,
@ -33,10 +34,13 @@ import {
} from '@hcengineering/notification'
import type { IntlString } from '@hcengineering/platform'
import setting from '@hcengineering/setting'
import { AnyComponent } from '@hcengineering/ui'
import workbench from '@hcengineering/workbench'
import notification from './plugin'
import { AnyComponent } from '@hcengineering/ui'
import view, { createAction } from '@hcengineering/model-view'
export { notificationId } from '@hcengineering/notification'
export { notificationOperation } from './migration'
export { notification as default }
export const DOMAIN_NOTIFICATION = 'notification' as Domain
@ -296,6 +300,3 @@ export function createModel (builder: Builder): void {
actions: [view.action.Delete, view.action.Open]
})
}
export { notificationOperation } from './migration'
export { notification as default }

View File

@ -18,6 +18,10 @@ import { Builder, Model, Prop, TypeRef } from '@hcengineering/model'
import core, { TDoc } from '@hcengineering/model-core'
import preference, { DOMAIN_PREFERENCE, Preference, SpacePreference } from '@hcengineering/preference'
export { preferenceId } from '@hcengineering/preference'
export { preferenceOperation } from './migration'
export { preference as default }
@Model(preference.class.Preference, core.class.Doc, DOMAIN_PREFERENCE)
export class TPreference extends TDoc implements Preference {
@Prop(TypeRef(core.class.Doc), core.string.AttachedTo)
@ -33,6 +37,3 @@ export class TSpacePreference extends TPreference implements SpacePreference {
export function createModel (builder: Builder): void {
builder.createModel(TPreference, TSpacePreference)
}
export { preference as default }
export { preferenceOperation } from './migration'

View File

@ -21,6 +21,7 @@ import type { Asset, IntlString, Resource } from '@hcengineering/platform'
import { ObjectSearchCategory, ObjectSearchFactory } from '@hcengineering/presentation/src/types'
import presentation from './plugin'
export { presentationId } from '@hcengineering/presentation/src/plugin'
export { default } from './plugin'
export { ObjectSearchCategory, ObjectSearchFactory }

View File

@ -39,20 +39,20 @@ import contact, { TOrganization, TPerson } from '@hcengineering/model-contact'
import core, { TAttachedDoc, TSpace } from '@hcengineering/model-core'
import presentation from '@hcengineering/model-presentation'
import tags from '@hcengineering/model-tags'
import task, { actionTemplates, DOMAIN_TASK, TSpaceWithStates, TTask } from '@hcengineering/model-task'
import task, { DOMAIN_TASK, TSpaceWithStates, TTask, actionTemplates } from '@hcengineering/model-task'
import tracker from '@hcengineering/model-tracker'
import view, { actionTemplates as viewTemplates, createAction } from '@hcengineering/model-view'
import view, { createAction, actionTemplates as viewTemplates } from '@hcengineering/model-view'
import workbench, { Application, createNavigateAction } from '@hcengineering/model-workbench'
import notification from '@hcengineering/notification'
import { getEmbeddedLabel, IntlString } from '@hcengineering/platform'
import { IntlString, getEmbeddedLabel } from '@hcengineering/platform'
import {
Applicant,
ApplicantMatch,
Candidate,
Candidates,
recruitId,
Vacancy,
VacancyList
VacancyList,
recruitId
} from '@hcengineering/recruit'
import setting from '@hcengineering/setting'
import { KeyBinding, ViewOptionsModel } from '@hcengineering/view'
@ -60,6 +60,10 @@ import recruit from './plugin'
import { createReviewModel, reviewTableConfig, reviewTableOptions } from './review'
import { TOpinion, TReview } from './review-model'
export { recruitId } from '@hcengineering/recruit'
export { recruitOperation } from './migration'
export { default } from './plugin'
@Model(recruit.class.Vacancy, task.class.SpaceWithStates)
@UX(recruit.string.Vacancy, recruit.icon.Vacancy, 'VCN', 'name')
export class TVacancy extends TSpaceWithStates implements Vacancy {
@ -1190,6 +1194,3 @@ export function createModel (builder: Builder): void {
recruit.action.MoveApplicant
)
}
export { recruitOperation } from './migration'
export { default } from './plugin'

View File

@ -60,7 +60,9 @@ export default mergeIds(recruitId, recruit, {
GotoAssigned: '' as IntlString,
GotoApplicants: '' as IntlString,
GotoRecruitApplication: '' as IntlString,
VacancyList: '' as IntlString
VacancyList: '' as IntlString,
ConfigLabel: '' as IntlString,
ConfigDescription: '' as IntlString
},
validator: {
ApplicantValidator: '' as Resource<<T extends Doc>(doc: T, client: Client) => Promise<Status>>

View File

@ -31,12 +31,15 @@ import {
TypeString,
UX
} from '@hcengineering/model'
import core, { TAttachedDoc, TClass } from '@hcengineering/model-core'
import { Request, RequestDecisionComment, RequestStatus, RequestPresenter } from '@hcengineering/request'
import request from './plugin'
import view from '@hcengineering/model-view'
import { TComment } from '@hcengineering/model-chunter'
import core, { TAttachedDoc, TClass } from '@hcengineering/model-core'
import view from '@hcengineering/model-view'
import { Request, RequestDecisionComment, RequestPresenter, RequestStatus } from '@hcengineering/request'
import { AnyComponent } from '@hcengineering/ui'
import request from './plugin'
export { requestId } from '@hcengineering/request'
export { default } from './plugin'
export const DOMAIN_REQUEST = 'request' as Domain
@ -105,5 +108,3 @@ export function createModel (builder: Builder): void {
request.ids.TxRequestCreate
)
}
export { default } from './plugin'

View File

@ -16,9 +16,11 @@
import { Builder } from '@hcengineering/model'
import serverCore from '@hcengineering/server-core'
import core from '@hcengineering/core'
import serverAttachment from '@hcengineering/server-attachment'
import serverCore from '@hcengineering/server-core'
export { serverAttachmentId } from '@hcengineering/server-attachment'
export function createModel (builder: Builder): void {
builder.createDoc(serverCore.class.Trigger, core.space.Model, {

View File

@ -16,8 +16,10 @@
import { Builder } from '@hcengineering/model'
import core, { Class, Doc } from '@hcengineering/core'
import serverCore, { ObjectDDParticipant } from '@hcengineering/server-core'
import serverCalendar from '@hcengineering/server-calendar'
import serverCore, { ObjectDDParticipant } from '@hcengineering/server-core'
export { serverCalendarId } from '@hcengineering/server-calendar'
export function createModel (builder: Builder): void {
builder.mixin<Class<Doc>, ObjectDDParticipant>(

View File

@ -20,6 +20,7 @@ import chunter from '@hcengineering/chunter'
import serverNotification from '@hcengineering/server-notification'
import serverCore, { ObjectDDParticipant } from '@hcengineering/server-core'
import serverChunter from '@hcengineering/server-chunter'
export { serverChunterId } from '@hcengineering/server-chunter'
export function createModel (builder: Builder): void {
builder.mixin(chunter.class.Channel, core.class.Class, serverNotification.mixin.HTMLPresenter, {

View File

@ -16,11 +16,12 @@
import { Builder } from '@hcengineering/model'
import serverCore from '@hcengineering/server-core'
import core from '@hcengineering/core'
import contact from '@hcengineering/contact'
import serverNotification from '@hcengineering/server-notification'
import core from '@hcengineering/core'
import serverContact from '@hcengineering/server-contact'
import serverCore from '@hcengineering/server-core'
import serverNotification from '@hcengineering/server-notification'
export { serverContactId } from '@hcengineering/server-contact'
export function createModel (builder: Builder): void {
builder.mixin(contact.class.Person, core.class.Class, serverNotification.mixin.HTMLPresenter, {

View File

@ -31,6 +31,8 @@ import core, {
import type { ObjectDDParticipant, Trigger, TriggerFunc } from '@hcengineering/server-core'
import serverCore from '@hcengineering/server-core'
export { serverCoreId } from '@hcengineering/server-core'
@Model(serverCore.class.Trigger, core.class.Doc, DOMAIN_MODEL)
export class TTrigger extends TDoc implements Trigger {
trigger!: Resource<TriggerFunc>

View File

@ -15,10 +15,11 @@
import { Builder } from '@hcengineering/model'
import contact from '@hcengineering/contact'
import core, { Class, Doc } from '@hcengineering/core'
import serverCore, { ObjectDDParticipant } from '@hcengineering/server-core'
import contact from '@hcengineering/contact'
import serverGmail from '@hcengineering/server-gmail'
export { serverGmailId } from '@hcengineering/server-gmail'
export function createModel (builder: Builder): void {
builder.mixin<Class<Doc>, ObjectDDParticipant>(

View File

@ -15,11 +15,13 @@
import { Builder } from '@hcengineering/model'
import serverCore from '@hcengineering/server-core'
import core from '@hcengineering/core'
import hr from '@hcengineering/hr'
import serverCore from '@hcengineering/server-core'
import serverHr from '@hcengineering/server-hr'
import serverNotification from '@hcengineering/server-notification'
import hr from '@hcengineering/hr'
export { serverHrId } from '@hcengineering/server-hr'
export function createModel (builder: Builder): void {
builder.createDoc(serverCore.class.Trigger, core.space.Model, {

View File

@ -20,6 +20,8 @@ import inventory from '@hcengineering/inventory'
import serverInventory from '@hcengineering/server-inventory'
import serverNotification from '@hcengineering/server-notification'
export { serverInventoryId } from '@hcengineering/server-inventory'
export function createModel (builder: Builder): void {
builder.mixin(inventory.class.Product, core.class.Class, serverNotification.mixin.HTMLPresenter, {
presenter: serverInventory.function.ProductHTMLPresenter

View File

@ -17,9 +17,11 @@ import { Builder } from '@hcengineering/model'
import core from '@hcengineering/core'
import lead from '@hcengineering/lead'
import serverNotification from '@hcengineering/server-notification'
import serverLead from '@hcengineering/server-lead'
import serverCore from '@hcengineering/server-core'
import serverLead from '@hcengineering/server-lead'
import serverNotification from '@hcengineering/server-notification'
export { serverLeadId } from '@hcengineering/server-lead'
export function createModel (builder: Builder): void {
builder.mixin(lead.class.Lead, core.class.Class, serverNotification.mixin.HTMLPresenter, {

View File

@ -16,11 +16,13 @@
import { Builder, Mixin } from '@hcengineering/model'
import serverCore from '@hcengineering/server-core'
import core from '@hcengineering/core'
import serverNotification, { HTMLPresenter, TextPresenter, Presenter } from '@hcengineering/server-notification'
import { Resource } from '@hcengineering/platform'
import { TClass } from '@hcengineering/model-core'
import { Resource } from '@hcengineering/platform'
import serverCore from '@hcengineering/server-core'
import serverNotification, { HTMLPresenter, Presenter, TextPresenter } from '@hcengineering/server-notification'
export { serverNotificationId } from '@hcengineering/server-notification'
@Mixin(serverNotification.mixin.HTMLPresenter, core.class.Class)
export class THTMLPresenter extends TClass implements HTMLPresenter {

View File

@ -25,6 +25,8 @@ import serverCore from '@hcengineering/server-core'
import chunter from '@hcengineering/model-chunter'
import recruit from '@hcengineering/model-recruit'
export { openAIId } from '@hcengineering/openai/src/plugin'
@Model(openai.class.OpenAIConfiguration, core.class.Configuration, DOMAIN_CONFIGURATION)
@UX(getEmbeddedLabel('OpenAI'))
export class TOpenAIConfiguration extends TConfiguration implements OpenAIConfiguration {

View File

@ -17,9 +17,11 @@ import { Builder } from '@hcengineering/model'
import core from '@hcengineering/core'
import recruit from '@hcengineering/recruit'
import serverCore from '@hcengineering/server-core'
import serverNotification from '@hcengineering/server-notification'
import serverRecruit from '@hcengineering/server-recruit'
import serverCore from '@hcengineering/server-core'
export { serverRecruitId } from '@hcengineering/server-recruit'
export function createModel (builder: Builder): void {
builder.mixin(recruit.class.Applicant, core.class.Class, serverNotification.mixin.HTMLPresenter, {

View File

@ -19,6 +19,8 @@ import core from '@hcengineering/core'
import serverCore from '@hcengineering/server-core'
import serverRequest from '@hcengineering/server-request'
export { serverRequestId } from '@hcengineering/server-request'
export function createModel (builder: Builder): void {
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
trigger: serverRequest.trigger.OnRequestUpdate

View File

@ -16,10 +16,12 @@
import { Builder } from '@hcengineering/model'
import serverCore from '@hcengineering/server-core'
import core from '@hcengineering/core'
import serverCore from '@hcengineering/server-core'
import serverSetting from '@hcengineering/server-setting'
export { serverSettingId } from '@hcengineering/server-setting'
export function createModel (builder: Builder): void {
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
trigger: serverSetting.trigger.OnIntegrationDisable

View File

@ -19,6 +19,8 @@ import serverCore, { ObjectDDParticipant } from '@hcengineering/server-core'
import serverTags from '@hcengineering/server-tags'
import tags from '@hcengineering/tags'
export { serverTagsId } from '@hcengineering/server-tags'
export function createModel (builder: Builder): void {
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
trigger: serverTags.trigger.onTagReference

View File

@ -15,4 +15,6 @@
import { Builder } from '@hcengineering/model'
export { serverTaskId } from '@hcengineering/server-task'
export function createModel (builder: Builder): void {}

View File

@ -15,11 +15,13 @@
import { Builder } from '@hcengineering/model'
import contact from '@hcengineering/contact'
import core, { Class, Doc } from '@hcengineering/core'
import serverCore, { ObjectDDParticipant } from '@hcengineering/server-core'
import contact from '@hcengineering/contact'
import serverTelegram from '@hcengineering/server-telegram'
export { serverTelegramId } from '@hcengineering/server-telegram'
export function createModel (builder: Builder): void {
builder.mixin<Class<Doc>, ObjectDDParticipant>(
contact.class.Channel,

View File

@ -13,12 +13,14 @@
// limitations under the License.
//
import { Builder } from '@hcengineering/model'
import core from '@hcengineering/core'
import { Builder } from '@hcengineering/model'
import serverCore from '@hcengineering/server-core'
import serverNotification from '@hcengineering/server-notification'
import serverTracker from '@hcengineering/server-tracker'
import tracker from '@hcengineering/tracker'
import serverNotification from '@hcengineering/server-notification'
export { serverTrackerId } from '@hcengineering/server-tracker'
export function createModel (builder: Builder): void {
builder.mixin(tracker.class.Issue, core.class.Class, serverNotification.mixin.HTMLPresenter, {

View File

@ -20,6 +20,8 @@ import { getEmbeddedLabel } from '@hcengineering/platform'
import core, { DOMAIN_CONFIGURATION } from '@hcengineering/core'
import translate, { TranslateConfiguration } from '@hcengineering/translate/src/plugin'
export { translateId } from '@hcengineering/translate/src/plugin'
@Model(translate.class.TranslateConfiguration, core.class.Configuration, DOMAIN_CONFIGURATION)
@UX(getEmbeddedLabel('Retranslation'))
export class TTranslateConfiguration extends TConfiguration implements TranslateConfiguration {

View File

@ -13,11 +13,13 @@
// limitations under the License.
//
import { Builder } from '@hcengineering/model'
import core from '@hcengineering/core'
import { Builder } from '@hcengineering/model'
import serverCore from '@hcengineering/server-core'
import serverView from '@hcengineering/server-view'
export { serverViewId } from '@hcengineering/server-view'
export function createModel (builder: Builder): void {
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
trigger: serverView.trigger.OnCustomAttributeRemove

View File

@ -14,10 +14,12 @@
//
import activity from '@hcengineering/activity'
import contact from '@hcengineering/contact'
import { Account, Domain, DOMAIN_MODEL, Ref } from '@hcengineering/core'
import { Builder, Mixin, Model } from '@hcengineering/model'
import core, { TClass, TConfiguration, TDoc } from '@hcengineering/model-core'
import view, { createAction } from '@hcengineering/model-view'
import notification from '@hcengineering/notification'
import type { Asset, IntlString } from '@hcengineering/platform'
import {
Editable,
@ -30,14 +32,16 @@ import {
UserMixin
} from '@hcengineering/setting'
import task from '@hcengineering/task'
import setting from './plugin'
import templates from '@hcengineering/templates'
import contact from '@hcengineering/contact'
import notification from '@hcengineering/notification'
import setting from './plugin'
import workbench from '@hcengineering/model-workbench'
import { AnyComponent } from '@hcengineering/ui'
export { settingId } from '@hcengineering/setting'
export { default } from './plugin'
export { settingOperation } from './migration'
export const DOMAIN_SETTING = 'setting' as Domain
@Model(setting.class.Integration, core.class.Doc, DOMAIN_SETTING)
@ -180,6 +184,19 @@ export function createModel (builder: Builder): void {
},
setting.ids.Owners
)
builder.createDoc(
setting.class.WorkspaceSettingCategory,
core.space.Model,
{
name: 'configuration',
label: setting.string.Configure,
icon: setting.icon.Setting,
component: setting.component.Configure,
order: 1001,
secured: true
},
setting.ids.Configure
)
builder.createDoc(
setting.class.WorkspaceSettingCategory,
core.space.Model,
@ -466,5 +483,3 @@ export function createModel (builder: Builder): void {
setting.templateField.OwnerPosition
)
}
export { settingOperation } from './migration'

View File

@ -28,7 +28,8 @@ export default mergeIds(settingId, setting, {
},
ids: {
TxIntegrationDisable: '' as Ref<TxViewlet>,
EnumSetting: '' as Ref<Doc>
EnumSetting: '' as Ref<Doc>,
Configure: '' as Ref<Doc>
},
component: {
EnumSetting: '' as AnyComponent,
@ -43,7 +44,8 @@ export default mergeIds(settingId, setting, {
CreateMixin: '' as AnyComponent,
InviteSetting: '' as AnyComponent,
ArrayEditor: '' as AnyComponent,
IntegrationPanel: '' as AnyComponent
IntegrationPanel: '' as AnyComponent,
Configure: '' as AnyComponent
},
category: {
Settings: '' as Ref<ActionCategory>

View File

@ -27,7 +27,7 @@ import type {
} from '@hcengineering/tags'
import tags from './plugin'
export { TagCategory, TagElement, TagReference } from '@hcengineering/tags'
export { TagCategory, TagElement, TagReference, tagsId } from '@hcengineering/tags'
export { tagsOperation } from './migration'
export { tags as default }

View File

@ -33,7 +33,7 @@ import {
UX
} from '@hcengineering/model'
import core, { TAttachedDoc, TClass, TDoc, TSpace, TStatus } from '@hcengineering/model-core'
import view, { actionTemplates as viewTemplates, createAction, template } from '@hcengineering/model-view'
import view, { createAction, template, actionTemplates as viewTemplates } from '@hcengineering/model-view'
import notification from '@hcengineering/notification'
import { IntlString } from '@hcengineering/platform'
import tags from '@hcengineering/tags'
@ -58,6 +58,7 @@ import { AnyComponent } from '@hcengineering/ui'
import { ViewAction } from '@hcengineering/view'
import task from './plugin'
export { taskId } from '@hcengineering/task'
export { createKanbanTemplate, createSequence, taskOperation } from './migration'
export { default } from './plugin'

View File

@ -39,8 +39,12 @@ import type {
TelegramMessage
} from '@hcengineering/telegram'
import templates from '@hcengineering/templates'
import telegram from './plugin'
import view from '@hcengineering/view'
import telegram from './plugin'
export { telegramId } from '@hcengineering/telegram'
export { telegramOperation } from './migration'
export { default } from './plugin'
export const DOMAIN_TELEGRAM = 'telegram' as Domain
@ -175,5 +179,3 @@ export function createModel (builder: Builder): void {
parentPropagate: false
})
}
export { telegramOperation } from './migration'

View File

@ -31,7 +31,9 @@ export default mergeIds(telegramId, telegram, {
Messages: '' as IntlString,
Telegram: '' as IntlString,
TelegramIntegrationDesc: '' as IntlString,
Status: '' as IntlString
Status: '' as IntlString,
ConfigLabel: '' as IntlString,
ConfigDescription: '' as IntlString
},
ids: {
TxMessage: '' as Ref<TxViewlet>,

View File

@ -18,6 +18,7 @@ import { Domain, DOMAIN_MODEL, IndexKind, Ref } from '@hcengineering/core'
import { Builder, Index, Model, Prop, TypeString, UX } from '@hcengineering/model'
import core, { TDoc, TSpace } from '@hcengineering/model-core'
import textEditor from '@hcengineering/model-text-editor'
import tracker from '@hcengineering/model-tracker'
import view, { createAction } from '@hcengineering/model-view'
import { IntlString, Resource } from '@hcengineering/platform'
import setting from '@hcengineering/setting'
@ -29,7 +30,9 @@ import type {
TemplateFieldFunc
} from '@hcengineering/templates'
import templates from './plugin'
import tracker from '@hcengineering/model-tracker'
export { templatesId } from '@hcengineering/templates'
export { templatesOperation } from './migration'
export const DOMAIN_TEMPLATES = 'templates' as Domain
@ -165,5 +168,3 @@ export function createModel (builder: Builder): void {
actions: [view.action.Open, tracker.action.NewRelatedIssue]
})
}
export { templatesOperation } from './migration'

View File

@ -21,6 +21,7 @@ import type { Asset, IntlString, Resource } from '@hcengineering/platform'
import { RefInputAction, RefInputActionItem } from '@hcengineering/text-editor/src/types'
import textEditor from './plugin'
export { textEditorId } from '@hcengineering/text-editor/src/plugin'
export { default } from './plugin'
export { RefInputAction, RefInputActionItem }

View File

@ -13,12 +13,13 @@
// limitations under the License.
//
import activity from '@hcengineering/activity'
import type { Employee, EmployeeAccount } from '@hcengineering/contact'
import contact from '@hcengineering/contact'
import {
DOMAIN_MODEL,
DateRangeMode,
Domain,
DOMAIN_MODEL,
FindOptions,
IndexKind,
Markup,
@ -46,7 +47,6 @@ import {
UX
} from '@hcengineering/model'
import attachment from '@hcengineering/model-attachment'
import activity from '@hcengineering/activity'
import chunter from '@hcengineering/model-chunter'
import core, { DOMAIN_SPACE, TAttachedDoc, TDoc, TSpace, TStatus, TType } from '@hcengineering/model-core'
import view, { actionTemplates, classPresenter, createAction } from '@hcengineering/model-view'
@ -81,6 +81,7 @@ import tracker from './plugin'
import presentation from '@hcengineering/model-presentation'
import { defaultPriorities, issuePriorities } from '@hcengineering/tracker-resources/src/types'
export { trackerId } from '@hcengineering/tracker'
export { trackerOperation } from './migration'
export { default } from './plugin'

View File

@ -36,7 +36,9 @@ export default mergeIds(trackerId, tracker, {
GotoTrackerApplication: '' as IntlString,
SearchIssue: '' as IntlString,
Parent: '' as IntlString,
CreatedOn: '' as IntlString
CreatedOn: '' as IntlString,
ConfigLabel: '' as IntlString,
ConfigDescription: '' as IntlString
},
activity: {
TxIssueCreated: '' as AnyComponent,

View File

@ -24,6 +24,7 @@ import type { AnyComponent, Location } from '@hcengineering/ui'
import type {
Action,
ActionCategory,
AllValuesFunc,
ArrayEditor,
AttributeEditor,
AttributeFilter,
@ -34,19 +35,22 @@ import type {
CollectionEditor,
CollectionPresenter,
Filter,
FilteredView,
FilterMode,
FilteredView,
GetAllValuesFunc,
IgnoreActions,
InlineAttributEditor,
KeyBinding,
KeyFilter,
LinkPresenter,
LinkProvider,
ListHeaderExtra,
ListItemPresenter,
ObjectEditor,
ObjectEditorHeader,
ObjectEditorFooter,
ObjectEditorHeader,
ObjectFactory,
ObjectPanel,
ObjectPresenter,
ObjectTitle,
ObjectValidator,
@ -57,18 +61,15 @@ import type {
ViewAction,
ViewActionInput,
ViewContext,
ViewOptions,
ViewOptionsModel,
Viewlet,
ViewletDescriptor,
ViewletPreference,
ViewOptionsModel,
ViewOptions,
AllValuesFunc,
GetAllValuesFunc,
LinkProvider,
ObjectPanel
ViewletPreference
} from '@hcengineering/view'
import view from './plugin'
export { viewId } from '@hcengineering/view'
export { viewOperation } from './migration'
export { ViewAction, Viewlet }

View File

@ -13,17 +13,18 @@
// limitations under the License.
//
import type { IntlString, Asset } from '@hcengineering/platform'
import { Class, DOMAIN_MODEL, Ref, Space } from '@hcengineering/core'
import { Model, Mixin, Builder, UX, Prop, TypeRef } from '@hcengineering/model'
import type { Application, SpaceView, ViewConfiguration, HiddenApplication } from '@hcengineering/workbench'
import view, { KeyBinding } from '@hcengineering/view'
import { createAction } from '@hcengineering/model-view'
import { Builder, Mixin, Model, Prop, TypeRef, UX } from '@hcengineering/model'
import preference, { TPreference } from '@hcengineering/model-preference'
import { createAction } from '@hcengineering/model-view'
import type { Asset, IntlString } from '@hcengineering/platform'
import view, { KeyBinding } from '@hcengineering/view'
import type { Application, HiddenApplication, SpaceView, ViewConfiguration } from '@hcengineering/workbench'
import core, { TDoc, TClass } from '@hcengineering/model-core'
import core, { TClass, TDoc } from '@hcengineering/model-core'
import workbench from './plugin'
export { workbenchId } from '@hcengineering/workbench'
export { Application }
@Model(workbench.class.Application, core.class.Doc, DOMAIN_MODEL)

View File

@ -14,7 +14,7 @@
// limitations under the License.
//
import { Plugin, IntlString } from '@hcengineering/platform'
import type { Class, Doc, Domain, Ref } from '../classes'
import type { Class, Data, Doc, Domain, PluginConfiguration, Ref } from '../classes'
import { Space, ClassifierKind, DOMAIN_MODEL } from '../classes'
import { createClient, ClientConnection } from '../client'
import core from '../component'
@ -118,9 +118,11 @@ describe('client', () => {
const spyCreate = jest.spyOn(TxProcessor, 'createDoc2Doc')
const spyUpdate = jest.spyOn(TxProcessor, 'updateDoc2Doc')
const pluginData1 = {
pluginId: 'testPlugin1',
transactions: []
const pluginData1: Data<PluginConfiguration> = {
pluginId: 'testPlugin1' as Plugin,
transactions: [],
configurable: true,
enabled: true
}
const txCreateDoc1 = txFactory.createTxCreateDoc(core.class.PluginConfiguration, core.space.Model, pluginData1)
txes.push(txCreateDoc1)
@ -134,8 +136,10 @@ describe('client', () => {
await client1.close()
const pluginData2 = {
pluginId: 'testPlugin2',
transactions: []
pluginId: 'testPlugin2' as Plugin,
transactions: [],
configurable: true,
enabled: true
}
const txCreateDoc2 = txFactory.createTxCreateDoc(core.class.PluginConfiguration, core.space.Model, pluginData2)
txes.push(txCreateDoc2)
@ -150,8 +154,10 @@ describe('client', () => {
await client2.close()
const pluginData3 = {
pluginId: 'testPlugin3',
transactions: [txCreateDoc1._id]
pluginId: 'testPlugin3' as Plugin,
transactions: [txCreateDoc1._id],
configurable: true,
enabled: true
}
const txUpdateDoc = txFactory.createTxUpdateDoc(
core.class.PluginConfiguration,

View File

@ -14,7 +14,7 @@
// limitations under the License.
//
import type { Asset, IntlString } from '@hcengineering/platform'
import type { Asset, IntlString, Plugin } from '@hcengineering/platform'
/**
* @public
@ -172,8 +172,19 @@ export interface Class<T extends Obj> extends Classifier {
* Define a set of plugin to model document bindings.
*/
export interface PluginConfiguration extends Doc {
pluginId: string
pluginId: Plugin
transactions: Ref<Doc>[]
label?: IntlString
icon?: Asset
description?: IntlString
enabled: boolean
// If specified, will allow user to enable/disable item.
configurable: boolean
// If defined, will only remove classes in list.
classFilter?: Ref<Class<Obj>>[]
}
/**

View File

@ -272,10 +272,12 @@ async function loadModel (
atxes.forEach((tx) => (tx.modifiedBy === core.account.System && !isEmployeeAccount(tx) ? systemTx : userTx).push(tx))
if (allowedPlugins !== undefined) {
if (allowedPlugins != null) {
fillConfiguration(systemTx, configs)
const excludedPlugins = Array.from(configs.values()).filter((it) => !allowedPlugins.includes(it.pluginId as Plugin))
fillConfiguration(userTx, configs)
const excludedPlugins = Array.from(configs.values()).filter(
(it) => !it.enabled || !allowedPlugins.includes(it.pluginId)
)
systemTx = pluginFilterTx(excludedPlugins, configs, systemTx)
}
@ -331,7 +333,22 @@ function pluginFilterTx (
if (a.pluginId === c.pluginId) {
const excluded = new Set<Ref<Tx>>()
for (const id of c.transactions) {
excluded.add(id as Ref<Tx>)
if (c.classFilter !== undefined) {
const filter = new Set(c.classFilter)
const tx = systemTx.find((it) => it._id === id)
if (
tx?._class === core.class.TxCreateDoc ||
tx?._class === core.class.TxUpdateDoc ||
tx?._class === core.class.TxRemoveDoc
) {
const cud = tx as TxCUD<Doc>
if (filter.has(cud.objectClass)) {
excluded.add(id as Ref<Tx>)
}
}
} else {
excluded.add(id as Ref<Tx>)
}
}
const exclude = systemTx.filter((t) => excluded.has(t._id))
console.log('exclude plugin', c.pluginId, exclude.length)

View File

@ -32,8 +32,8 @@ import type {
FullTextData,
FullTextSearchContext,
Hyperlink,
IndexingConfiguration,
IndexStageState,
IndexingConfiguration,
Interface,
Obj,
PluginConfiguration,
@ -49,9 +49,9 @@ import { Status, StatusCategory } from './status'
import type {
Tx,
TxApplyIf,
TxCUD,
TxCollectionCUD,
TxCreateDoc,
TxCUD,
TxMixin,
TxModelUpgrade,
TxRemoveDoc,
@ -133,7 +133,8 @@ export default plugin(coreId, {
Configuration: '' as Ref<Space>
},
account: {
System: '' as Ref<Account>
System: '' as Ref<Account>,
ConfigUser: '' as Ref<Account>
},
status: {
ObjectNotFound: '' as StatusCode<{ _id: Ref<Doc> }>,

View File

@ -74,11 +74,18 @@ export class Hierarchy {
return typeof (d as any)[mixin] === 'object'
}
classHierarchyMixin<D extends Doc, M extends D>(_class: Ref<Class<D>>, mixin: Ref<Mixin<M>>): M | undefined {
classHierarchyMixin<D extends Doc, M extends D>(
_class: Ref<Class<D>>,
mixin: Ref<Mixin<M>>,
filter?: (value: M) => boolean
): M | undefined {
let clazz = this.getClass(_class)
while (true) {
if (this.hasMixin(clazz, mixin)) {
return this.as(clazz, mixin) as any as M
const m = this.as(clazz, mixin) as any as M
if (m !== undefined && (filter?.(m) ?? true)) {
return m
}
}
if (clazz.extends === undefined) return
clazz = this.getClass(clazz.extends)

View File

@ -14,10 +14,10 @@
// limitations under the License.
//
import type { Resource, Plugin } from './platform'
import { Status, Severity, PlatformError } from './status'
import { _parseId } from './ident'
import { monitor } from './event'
import { _parseId } from './ident'
import type { Plugin, Resource } from './platform'
import { PlatformError, Severity, Status } from './status'
import platform from './platform'
@ -105,3 +105,11 @@ export async function getResource<T> (resource: Resource<T>): Promise<T> {
cachedResource.set(resource, value)
return value
}
/**
* @public
*/
export function getResourcePlugin<T> (resource: Resource<T>): Plugin {
const info = _parseId(resource)
return info.component
}

View File

@ -0,0 +1,65 @@
//
// 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.
//
import core, { PluginConfiguration, SortingOrder } from '@hcengineering/core'
import { Plugin, Resource, getResourcePlugin } from '@hcengineering/platform'
import { writable } from 'svelte/store'
import { createQuery } from '.'
import { statusStore } from './status'
export { statusStore }
/**
* @public
*/
export class ConfigurationManager {
constructor (readonly list: PluginConfiguration[], readonly configuration: Map<Plugin, PluginConfiguration>) {}
has (plugin: Plugin): boolean {
return this.configuration.get(plugin)?.enabled !== false
}
hasResource<T>(resource?: Resource<T> | null): boolean {
if (resource == null) {
return false
}
return this.has(getResourcePlugin(resource))
}
}
// Issue status live query
export let configuration = new ConfigurationManager([], new Map())
export const configurationStore = writable<ConfigurationManager>(configuration)
const configQuery = createQuery(true)
/**
* @public
*/
export function hasResource<T> (resource?: Resource<T>): boolean {
return configuration.hasResource(resource)
}
configQuery.query(
core.class.PluginConfiguration,
{},
(res) => {
if (configuration.list.length > 0) {
// Configuration
location.reload()
}
configuration = new ConfigurationManager(res, new Map(res.map((it) => [it.pluginId, it])))
configurationStore.set(configuration)
},
{ sort: { label: SortingOrder.Ascending } }
)

View File

@ -43,6 +43,7 @@ export * from './types'
export * from './utils'
export * from './drafts'
export { presentationId }
export * from './configuration'
addStringsLoader(presentationId, async (lang: string) => {
return await import(`../lang/${lang}.json`)

View File

@ -127,7 +127,7 @@ export async function setClient (_client: Client): Promise<void> {
txListeners.forEach((it) => it(tx))
}
if (needRefresh) {
if (needRefresh || globalQueries.length > 0) {
await refreshClient()
}
}
@ -187,6 +187,15 @@ export class LiveQuery {
callback: (result: FindResult<T>) => void,
options: FindOptions<T> | undefined
): Promise<void> {
if (pipeline === undefined) {
// We need remember values to perform refresh.
this.oldCallback = callback
this.oldClass = _class
this.oldOptions = options
this.oldQuery = query
return
}
const id = ++this.reqId
const piplineQuery = await pipeline.subscribe(_class, query, options, () => {
// Refresh query if pipeline decide it is required.

View File

@ -16,7 +16,7 @@
import activity, { ActivityFilter, DisplayTx } from '@hcengineering/activity'
import { Class, Doc, Ref } from '@hcengineering/core'
import { IntlString, getResource } from '@hcengineering/platform'
import { getClient } from '@hcengineering/presentation'
import { getClient, hasResource } from '@hcengineering/presentation'
import { ActionIcon, AnyComponent, Icon, Label, eventToHTMLElement, showPopup } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import activityPlg from '../plugin'
@ -51,7 +51,9 @@
function getAdditionalComponent (_class: Ref<Class<Doc>>): AnyComponent | undefined {
const hierarchy = client.getHierarchy()
const mixin = hierarchy.classHierarchyMixin(_class, activity.mixin.ExtraActivityComponent)
const mixin = hierarchy.classHierarchyMixin(_class, activity.mixin.ExtraActivityComponent, (m) =>
hasResource(m.component)
)
if (mixin !== undefined) {
return mixin.component
}

View File

@ -52,7 +52,7 @@ async function createPseudoViewlet (
}
// Check if it is attached doc and collection have title override.
const presenter = await getObjectPresenter(client, dtx.tx.objectClass, { key: 'doc-presenter' })
const presenter = await getObjectPresenter(client, dtx.tx.objectClass, { key: 'doc-presenter' }, false, false)
if (presenter !== undefined) {
let collection = ''
if (dtx.collectionAttribute?.label !== undefined) {

View File

@ -11,6 +11,8 @@
"Attribute": "Attribute",
"MapField": "Map...",
"BitrixImport": "Synchronize with Bitrix",
"AddMapping": "Add entity mapping"
"AddMapping": "Add entity mapping",
"ConfigLabel": "Bitrix24",
"ConfigDescription": "Extension for Bitrix 24 integration"
}
}

View File

@ -11,6 +11,8 @@
"Attribute": "Attribute",
"MapField": "Map...",
"BitrixImport": "Synchronize with Bitrix",
"AddMapping": "Добавить отображение"
"AddMapping": "Добавить отображение",
"ConfigLabel": "Bitrix24",
"ConfigDescription": "Extension for Bitrix 24 integration"
}
}

View File

@ -101,6 +101,8 @@
"RemoveCover": "Remove cover",
"DeleteChecklist": "Delete checklist",
"DeleteChecklistConfirm": "Deleting a checklist is permanent and there is no way to get it back.",
"ConvertToCard": "Convert to card"
"ConvertToCard": "Convert to card",
"ConfigLabel": "Board",
"ConfigDescription": "Extension to manage Kanban boards."
}
}

View File

@ -101,6 +101,8 @@
"RemoveCover": "Удалить обложку",
"DeleteChecklist": "Удалить список задач",
"DeleteChecklistConfirm": "Удаление списка задач необратимо, и не будет возможности его вернуть.",
"ConvertToCard": "Конвертировать в карточку"
"ConvertToCard": "Конвертировать в карточку",
"ConfigLabel": "Доски",
"ConfigDescription": "Расширение для управления канбан досками."
}
}

View File

@ -37,6 +37,8 @@
"AllDay": "All day",
"AndMore": "And {count} more",
"CreateEvent": "Create event",
"EventFor": "Event for: "
"EventFor": "Event for: ",
"ConfigLabel": "Calendar",
"ConfigDescription": "Extension to see calendar with Events"
}
}

View File

@ -37,6 +37,8 @@
"AllDay": "Весь день",
"AndMore": "И еще {count}",
"CreateEvent": "Создать событие",
"EventFor": "Событие для: "
"EventFor": "Событие для: ",
"ConfigLabel": "Календаоь",
"ConfigDescription": "Расширение для календаря с событиями"
}
}

View File

@ -65,6 +65,8 @@
"NoResults": "No results",
"CopyLink": "Copy link",
"FilterComments": "Comments",
"FilterBacklinks": "Backlinks"
"FilterBacklinks": "Backlinks",
"ConfigLabel": "Chat",
"ConfigDescription": "Extension to perform text communications"
}
}

View File

@ -65,6 +65,8 @@
"NoResults": "Нет результатов",
"CopyLink": "Копировать ссылку",
"FilterComments": "Коментарии",
"FilterBacklinks": "Упоминания"
"FilterBacklinks": "Упоминания",
"ConfigLabel": "Чат",
"ConfigDescription": "Расширение для текстовых переписок"
}
}

View File

@ -48,7 +48,7 @@ export default async () => {
return connect(url.href, upgradeHandler, onUpgrade, onUnauthorized, onConnect)
},
filterModel ? getPlugins() : undefined
filterModel ? [...getPlugins(), ...(getMetadata(clientPlugin.metadata.ExtraPlugins) ?? [])] : undefined
)
// Check if we had dev hook for client.
client = hookClient(client)

View File

@ -76,7 +76,8 @@ export default plugin(clientId, {
metadata: {
ClientHook: '' as Metadata<Resource<ClientHook>>,
ClientSocketFactory: '' as Metadata<ClientSocketFactory>,
FilterModel: '' as Metadata<boolean>
FilterModel: '' as Metadata<boolean>,
ExtraPlugins: '' as Metadata<Plugin[]>
},
function: {
GetClient: '' as Resource<ClientFactory>

View File

@ -93,6 +93,8 @@
"CategoryCurrentUser": "Current user",
"CategoryOther": "Other",
"NumberMembers": "{count, plural, =0 {no members} =1 {1 member} other {# members}}",
"Position": "Position"
"Position": "Position",
"ConfigLabel": "Contacts",
"ConfigDescription": "Extension to hold information about all Employees and other Person/Organization contacts."
}
}

View File

@ -93,6 +93,8 @@
"CategoryProjectLead": "Руководитель проекта",
"CategoryProjectMembers": "Участники проекта",
"CategoryOther": "Прочие",
"Position": "Должность"
"Position": "Должность",
"ConfigLabel": "Контакты",
"ConfigDescription": "Расширение по работе с сотрудниками и другими контактами."
}
}

View File

@ -121,7 +121,7 @@
</div>
<div class="flex-grow flex-col">
<div class="flex-grow flex-col">
<div class="name">
<div class="name select-text">
{#if owner}
<EditBox
placeholder={contact.string.PersonFirstNamePlaceholder}
@ -134,7 +134,7 @@
{firstName}
{/if}
</div>
<div class="name">
<div class="name select-text">
{#if owner}
<EditBox
placeholder={contact.string.PersonLastNamePlaceholder}

Some files were not shown because too many files have changed in this diff Show More