mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-28 20:45:00 +02:00
Merge branch 'develop' into staging-new
Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
Vendored
+1
-1
@@ -97,7 +97,7 @@
|
||||
"MODEL_JSON": "${workspaceRoot}/models/all/bundle/model.json",
|
||||
// "SERVER_PROVIDER":"uweb"
|
||||
"SERVER_PROVIDER": "ws",
|
||||
"MODEL_VERSION": "0.7.331",
|
||||
"MODEL_VERSION": "0.7.343",
|
||||
// "version": "0.7.0",
|
||||
"COMMUNICATION_API_ENABLED": "true",
|
||||
"ELASTIC_INDEX_NAME": "local_storage_index",
|
||||
|
||||
+188
-139
File diff suppressed because one or more lines are too long
+3
-1
@@ -54,7 +54,9 @@ commit_preprocessors = [
|
||||
{ pattern = '^QFix ', replace = "fix: " },
|
||||
{ pattern = '^qfix ', replace = "fix: " },
|
||||
{ pattern = '^QFIX: ', replace = "fix: " },
|
||||
{ pattern = '^Add ', replace = "feat: " },
|
||||
{ pattern = '^Missing ', replace = "fix: Missing " },
|
||||
{ pattern = '^Add missing ', replace = "fix: Add missing " },
|
||||
{ pattern = '^Add ', replace = "feat: Add " },
|
||||
{ pattern = '^Update ', replace = "chore: " },
|
||||
{ pattern = '^Remove ', replace = "chore: " },
|
||||
{ pattern = '^Bump ', replace = "chore: " },
|
||||
|
||||
Generated
+7
-42
@@ -6815,6 +6815,9 @@ importers:
|
||||
'@hcengineering/chunter':
|
||||
specifier: workspace:^0.7.0
|
||||
version: link:../../plugins/chunter
|
||||
'@hcengineering/communication':
|
||||
specifier: workspace:^0.7.0
|
||||
version: link:../../plugins/communication
|
||||
'@hcengineering/contact':
|
||||
specifier: workspace:^0.7.0
|
||||
version: link:../../plugins/contact
|
||||
@@ -17320,6 +17323,9 @@ importers:
|
||||
'@hcengineering/account-client':
|
||||
specifier: workspace:^0.7.21
|
||||
version: link:../../foundations/core/packages/account-client
|
||||
'@hcengineering/activity':
|
||||
specifier: workspace:^0.7.0
|
||||
version: link:../activity
|
||||
'@hcengineering/analytics':
|
||||
specifier: workspace:^0.7.17
|
||||
version: link:../../foundations/core/packages/analytics
|
||||
@@ -61252,7 +61258,7 @@ snapshots:
|
||||
node-loader@2.0.0(webpack@5.102.1):
|
||||
dependencies:
|
||||
loader-utils: 2.0.4
|
||||
webpack: 5.102.1
|
||||
webpack: 5.102.1(@swc/core@1.15.1)(esbuild@0.25.12)(webpack-cli@5.1.4)
|
||||
|
||||
node-localstorage@2.2.1:
|
||||
dependencies:
|
||||
@@ -63283,15 +63289,6 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@swc/core': 1.15.1
|
||||
|
||||
terser-webpack-plugin@5.3.14(webpack@5.102.1):
|
||||
dependencies:
|
||||
'@jridgewell/trace-mapping': 0.3.31
|
||||
jest-worker: 27.5.1
|
||||
schema-utils: 4.3.3
|
||||
serialize-javascript: 6.0.2
|
||||
terser: 5.44.1
|
||||
webpack: 5.102.1
|
||||
|
||||
terser@5.44.1:
|
||||
dependencies:
|
||||
'@jridgewell/source-map': 0.3.11
|
||||
@@ -63958,38 +63955,6 @@ snapshots:
|
||||
|
||||
webpack-sources@3.3.3: {}
|
||||
|
||||
webpack@5.102.1:
|
||||
dependencies:
|
||||
'@types/eslint-scope': 3.7.7
|
||||
'@types/estree': 1.0.8
|
||||
'@types/json-schema': 7.0.15
|
||||
'@webassemblyjs/ast': 1.14.1
|
||||
'@webassemblyjs/wasm-edit': 1.14.1
|
||||
'@webassemblyjs/wasm-parser': 1.14.1
|
||||
acorn: 8.15.0
|
||||
acorn-import-phases: 1.0.4(acorn@8.15.0)
|
||||
browserslist: 4.28.1
|
||||
chrome-trace-event: 1.0.4
|
||||
enhanced-resolve: 5.18.3
|
||||
es-module-lexer: 1.7.0
|
||||
eslint-scope: 5.1.1
|
||||
events: 3.3.0
|
||||
glob-to-regexp: 0.4.1
|
||||
graceful-fs: 4.2.11
|
||||
json-parse-even-better-errors: 2.3.1
|
||||
loader-runner: 4.3.1
|
||||
mime-types: 2.1.35
|
||||
neo-async: 2.6.2
|
||||
schema-utils: 4.3.3
|
||||
tapable: 2.3.0
|
||||
terser-webpack-plugin: 5.3.14(webpack@5.102.1)
|
||||
watchpack: 2.4.4
|
||||
webpack-sources: 3.3.3
|
||||
transitivePeerDependencies:
|
||||
- '@swc/core'
|
||||
- esbuild
|
||||
- uglify-js
|
||||
|
||||
webpack@5.102.1(@swc/core@1.15.1):
|
||||
dependencies:
|
||||
'@types/eslint-scope': 3.7.7
|
||||
|
||||
@@ -1 +1 @@
|
||||
"0.7.340"
|
||||
"0.7.343"
|
||||
|
||||
@@ -488,7 +488,6 @@ export async function configurePlatform() {
|
||||
setMetadata(textEditor.metadata.Collaborator, config.COLLABORATOR)
|
||||
setMetadata(communication.metadata.Enabled, config.COMMUNICATION_API_ENABLED === 'true')
|
||||
|
||||
|
||||
if (config.MODEL_VERSION != null) {
|
||||
console.log('Minimal Model version requirement', config.MODEL_VERSION)
|
||||
setMetadata(presentation.metadata.ModelVersion, config.MODEL_VERSION)
|
||||
|
||||
@@ -944,6 +944,7 @@ export type SocialKey = Pick<SocialId, 'type' | 'value'>
|
||||
|
||||
export interface ClassCollaborators<T extends Doc> extends Doc {
|
||||
attachedTo: Ref<Class<T>>
|
||||
allFields?: boolean // for all (PersonId | Ref<Employee> | PersonId[] | Ref<Employee>[]) attributes
|
||||
fields: (keyof T)[] // PersonId | Ref<Employee> | PersonId[] | Ref<Employee>[]
|
||||
provideSecurity?: boolean // If true, will provide security for collaborators
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
"dependencies": {
|
||||
"@hcengineering/activity": "workspace:^0.7.0",
|
||||
"@hcengineering/contact": "workspace:^0.7.0",
|
||||
"@hcengineering/communication": "workspace:^0.7.0",
|
||||
"@hcengineering/core": "workspace:^0.7.24",
|
||||
"@hcengineering/model": "workspace:^0.7.17",
|
||||
"@hcengineering/chunter": "workspace:^0.7.0",
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
import activity from '@hcengineering/activity'
|
||||
import communication from '@hcengineering/communication'
|
||||
import {
|
||||
type CanCreateCardResource,
|
||||
type Card,
|
||||
@@ -37,6 +38,7 @@ import core, {
|
||||
AccountRole,
|
||||
type Blobs,
|
||||
type Class,
|
||||
type ClassCollaborators,
|
||||
ClassifierKind,
|
||||
type CollectionSize,
|
||||
type Doc,
|
||||
@@ -859,6 +861,12 @@ export function createModel (builder: Builder): void {
|
||||
})
|
||||
|
||||
createPublicLinkAction(builder, card.class.Card, card.action.PublicLink)
|
||||
|
||||
builder.createDoc<ClassCollaborators<Card>>(core.class.ClassCollaborators, core.space.Model, {
|
||||
attachedTo: card.class.Card,
|
||||
fields: ['modifiedBy'],
|
||||
allFields: true
|
||||
})
|
||||
}
|
||||
|
||||
function defineTabs (builder: Builder): void {
|
||||
@@ -923,6 +931,32 @@ function defineTabs (builder: Builder): void {
|
||||
card.section.Relations
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
card.class.CardSection,
|
||||
core.space.Model,
|
||||
{
|
||||
label: activity.string.Messages,
|
||||
component: card.sectionComponent.OldMessagesSection,
|
||||
order: 1000,
|
||||
navigation: [],
|
||||
checkVisibility: card.function.CheckOldMessagesSectionVisibility
|
||||
},
|
||||
card.section.OldMessages
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
card.class.CardSection,
|
||||
core.space.Model,
|
||||
{
|
||||
label: activity.string.Messages,
|
||||
component: card.sectionComponent.CommunicationMessagesSection,
|
||||
order: 1000,
|
||||
navigation: [],
|
||||
checkVisibility: card.function.CheckCommunicationMessagesSectionVisibility
|
||||
},
|
||||
communication.ids.CardMessagesSection
|
||||
)
|
||||
|
||||
builder.createDoc<Viewlet>(view.class.Viewlet, core.space.Model, {
|
||||
attachTo: card.class.FavoriteCard,
|
||||
descriptor: view.viewlet.Table,
|
||||
|
||||
@@ -17,6 +17,8 @@ import cardPlugin, { cardId, DOMAIN_CARD, type Card, type Role } from '@hcengine
|
||||
import core, {
|
||||
DOMAIN_MODEL,
|
||||
TxOperations,
|
||||
type Class,
|
||||
type ClassPermission,
|
||||
type Client,
|
||||
type Data,
|
||||
type Doc,
|
||||
@@ -121,11 +123,169 @@ export const cardOperation: MigrateOperation = {
|
||||
state: 'version-for-versionable-types',
|
||||
mode: 'upgrade',
|
||||
func: addVersionForVersionableTypes
|
||||
},
|
||||
{
|
||||
state: 'migrate-restricted-permissions',
|
||||
mode: 'upgrade',
|
||||
func: migrateRestrictedPermissions
|
||||
}
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
async function migrateRestrictedPermissions (_client: MigrationUpgradeClient): Promise<void> {
|
||||
const client = new TxOperations(_client, core.account.System)
|
||||
const hierarchy = client.getHierarchy()
|
||||
const desc = hierarchy.getDescendants(card.class.Card)
|
||||
const permissions = await client.findAll(core.class.ClassPermission, { objectClass: { $in: desc } })
|
||||
const restrictedTargets = new Set<Ref<Class<Doc>>>()
|
||||
for (const perm of permissions) {
|
||||
if (perm.targetClass !== undefined) {
|
||||
restrictedTargets.add(perm.targetClass)
|
||||
}
|
||||
}
|
||||
|
||||
const targets = await client.findAll(card.class.MasterTag, { _id: { $in: [...restrictedTargets] } })
|
||||
|
||||
for (const masterTag of targets) {
|
||||
const isMixin = hierarchy.isMixin(masterTag._id)
|
||||
const objectClass = hierarchy.getBaseClass(masterTag._id)
|
||||
if (isMixin) {
|
||||
await client.createDoc(
|
||||
core.class.ClassPermission,
|
||||
core.space.Model,
|
||||
{
|
||||
objectClass,
|
||||
txClass: core.class.TxMixin,
|
||||
txMatch: {
|
||||
mixin: masterTag._id
|
||||
},
|
||||
scope: 'space',
|
||||
forbid: false,
|
||||
label: card.string.AddTagPermission,
|
||||
description: masterTag.label,
|
||||
targetClass: masterTag._id
|
||||
},
|
||||
`${masterTag._id}_create_allowed` as Ref<ClassPermission>
|
||||
)
|
||||
await client.createDoc(
|
||||
core.class.ClassPermission,
|
||||
core.space.Model,
|
||||
{
|
||||
objectClass,
|
||||
txClass: core.class.TxMixin,
|
||||
txMatch: {
|
||||
mixin: masterTag._id
|
||||
},
|
||||
scope: 'space',
|
||||
forbid: true,
|
||||
label: card.string.ForbidAddTagPermission,
|
||||
description: masterTag.label,
|
||||
targetClass: masterTag._id
|
||||
},
|
||||
`${masterTag._id}_create_forbidden` as Ref<ClassPermission>
|
||||
)
|
||||
const key = `operations.$unset.${masterTag._id}`
|
||||
await client.createDoc(
|
||||
core.class.ClassPermission,
|
||||
core.space.Model,
|
||||
{
|
||||
objectClass,
|
||||
txClass: core.class.TxUpdateDoc,
|
||||
txMatch: {
|
||||
[key]: {
|
||||
$exists: true
|
||||
}
|
||||
},
|
||||
scope: 'space',
|
||||
forbid: false,
|
||||
label: card.string.RemoveTag,
|
||||
description: masterTag.label,
|
||||
targetClass: masterTag._id
|
||||
},
|
||||
`${masterTag._id}_remove_allowed` as Ref<ClassPermission>
|
||||
)
|
||||
await client.createDoc(
|
||||
core.class.ClassPermission,
|
||||
core.space.Model,
|
||||
{
|
||||
objectClass,
|
||||
txClass: core.class.TxUpdateDoc,
|
||||
txMatch: {
|
||||
[key]: { $exists: true }
|
||||
},
|
||||
scope: 'space',
|
||||
forbid: true,
|
||||
label: card.string.ForbidRemoveTag,
|
||||
description: masterTag.label,
|
||||
targetClass: masterTag._id
|
||||
},
|
||||
`${masterTag._id}_remove_forbidden` as Ref<ClassPermission>
|
||||
)
|
||||
} else {
|
||||
await client.createDoc(
|
||||
core.class.ClassPermission,
|
||||
core.space.Model,
|
||||
{
|
||||
objectClass,
|
||||
txClass: core.class.TxCreateDoc,
|
||||
scope: 'space',
|
||||
forbid: false,
|
||||
label: card.string.CreateCardPermission,
|
||||
description: masterTag.label,
|
||||
targetClass: masterTag._id
|
||||
},
|
||||
`${masterTag._id}_create_allowed` as Ref<ClassPermission>
|
||||
)
|
||||
await client.createDoc(
|
||||
core.class.ClassPermission,
|
||||
core.space.Model,
|
||||
{
|
||||
objectClass,
|
||||
txClass: core.class.TxCreateDoc,
|
||||
scope: 'space',
|
||||
forbid: true,
|
||||
label: card.string.ForbidCreateCardPermission,
|
||||
description: masterTag.label,
|
||||
targetClass: masterTag._id
|
||||
},
|
||||
`${masterTag._id}_create_forbidden` as Ref<ClassPermission>
|
||||
)
|
||||
await client.createDoc(
|
||||
core.class.ClassPermission,
|
||||
core.space.Model,
|
||||
{
|
||||
objectClass,
|
||||
txClass: core.class.TxRemoveDoc,
|
||||
scope: 'space',
|
||||
forbid: false,
|
||||
label: card.string.RemoveCard,
|
||||
description: masterTag.label,
|
||||
targetClass: masterTag._id
|
||||
},
|
||||
`${masterTag._id}_remove_allowed` as Ref<ClassPermission>
|
||||
)
|
||||
await client.createDoc(
|
||||
core.class.ClassPermission,
|
||||
core.space.Model,
|
||||
{
|
||||
objectClass,
|
||||
txClass: core.class.TxRemoveDoc,
|
||||
txMatch: {
|
||||
objectClass: masterTag._id
|
||||
},
|
||||
scope: 'space',
|
||||
forbid: true,
|
||||
label: card.string.ForbidRemoveCard,
|
||||
description: masterTag.label,
|
||||
targetClass: masterTag._id
|
||||
},
|
||||
`${masterTag._id}_remove_forbidden` as Ref<ClassPermission>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function addVersionForVersionableTypes (client: MigrationUpgradeClient): Promise<void> {
|
||||
const txOp = new TxOperations(client, core.account.System)
|
||||
const versionableTypes = await client.findAll(card.class.MasterTag, {})
|
||||
|
||||
@@ -17,7 +17,7 @@ import { type Card, cardId } from '@hcengineering/card'
|
||||
import card from '@hcengineering/card-resources/src/plugin'
|
||||
import type { Client, Doc, Ref } from '@hcengineering/core'
|
||||
import {} from '@hcengineering/core'
|
||||
import { type IntlString, mergeIds, type Resource } from '@hcengineering/platform'
|
||||
import { mergeIds, type Resource } from '@hcengineering/platform'
|
||||
import { type TagCategory } from '@hcengineering/tags'
|
||||
import { type Location, type ResolvedLocation } from '@hcengineering/ui/src/types'
|
||||
import { type Action, type ActionCategory, type ViewAction } from '@hcengineering/view'
|
||||
@@ -39,28 +39,6 @@ export default mergeIds(cardId, card, {
|
||||
PublicLink: '' as Ref<Action<Doc, any>>,
|
||||
Duplicate: '' as Ref<Action>
|
||||
},
|
||||
string: {
|
||||
CreateCardPersmissionDescription: '' as IntlString,
|
||||
UpdateCardPersmissionDescription: '' as IntlString,
|
||||
RemoveCardPersmissionDescription: '' as IntlString,
|
||||
AddTagPersmissionDescription: '' as IntlString,
|
||||
RemoveTagPersmissionDescription: '' as IntlString,
|
||||
RemoveCard: '' as IntlString,
|
||||
UpdateCard: '' as IntlString,
|
||||
CreateCardPermission: '' as IntlString,
|
||||
AddTagPermission: '' as IntlString,
|
||||
RemoveTag: '' as IntlString,
|
||||
ForbidCreateCardPersmissionDescription: '' as IntlString,
|
||||
ForbidUpdateCardPersmissionDescription: '' as IntlString,
|
||||
ForbidRemoveCardPersmissionDescription: '' as IntlString,
|
||||
ForbidAddTagPersmissionDescription: '' as IntlString,
|
||||
ForbidRemoveTagPersmissionDescription: '' as IntlString,
|
||||
ForbidRemoveCard: '' as IntlString,
|
||||
ForbidUpdateCard: '' as IntlString,
|
||||
ForbidCreateCardPermission: '' as IntlString,
|
||||
ForbidAddTagPermission: '' as IntlString,
|
||||
ForbidRemoveTag: '' as IntlString
|
||||
},
|
||||
category: {
|
||||
Card: '' as Ref<ActionCategory>,
|
||||
Labels: '' as Ref<TagCategory>
|
||||
@@ -79,6 +57,8 @@ export default mergeIds(cardId, card, {
|
||||
GetCardLink: '' as Resource<(doc: Doc, props: Record<string, any>) => Promise<Location>>,
|
||||
CardCustomLinkMatch: '' as Resource<(doc: Doc) => boolean>,
|
||||
CardCustomLinkEncode: '' as Resource<(doc: Doc) => Location>,
|
||||
CheckRelationsSectionVisibility: '' as Resource<(doc: Card) => Promise<boolean>>
|
||||
CheckRelationsSectionVisibility: '' as Resource<(doc: Card) => Promise<boolean>>,
|
||||
CheckOldMessagesSectionVisibility: '' as Resource<(doc: Card) => Promise<boolean>>,
|
||||
CheckCommunicationMessagesSectionVisibility: '' as Resource<(doc: Card) => Promise<boolean>>
|
||||
}
|
||||
})
|
||||
|
||||
@@ -413,6 +413,7 @@ export class TCustomSequence extends TSequence implements CustomSequence {
|
||||
@Model(core.class.ClassCollaborators, core.class.Doc, DOMAIN_MODEL)
|
||||
export class TClassCollaborators extends TDoc implements ClassCollaborators<Doc> {
|
||||
attachedTo!: Ref<Class<Doc>>
|
||||
allFields?: boolean
|
||||
fields!: (keyof Doc)[]
|
||||
provideSecurity?: boolean
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ import {
|
||||
type CheckFunc,
|
||||
type ContextId,
|
||||
type CreatedContext,
|
||||
type ProcessCustomEvent,
|
||||
type EventButton,
|
||||
type Execution,
|
||||
type ExecutionContext,
|
||||
type ExecutionError,
|
||||
@@ -60,6 +60,7 @@ import {
|
||||
type MethodParams,
|
||||
type Process,
|
||||
type ProcessContext,
|
||||
type ProcessCustomEvent,
|
||||
type ProcessFunction,
|
||||
type ProcessToDo,
|
||||
type State,
|
||||
@@ -67,8 +68,7 @@ import {
|
||||
type Transition,
|
||||
type Trigger,
|
||||
type UpdateCriteriaComponent,
|
||||
processId,
|
||||
type EventButton
|
||||
processId
|
||||
} from '@hcengineering/process'
|
||||
import time from '@hcengineering/time'
|
||||
import { type AnyComponent } from '@hcengineering/ui'
|
||||
@@ -616,6 +616,7 @@ export function createModel (builder: Builder): void {
|
||||
{
|
||||
label: process.string.Processes,
|
||||
component: process.component.ProcessesCardSection,
|
||||
checkVisibility: process.function.CheckProcessSectionVisibility,
|
||||
order: 350,
|
||||
navigation: []
|
||||
},
|
||||
|
||||
@@ -1367,6 +1367,10 @@ export function createModel (builder: Builder): void {
|
||||
searchDisabled: true
|
||||
})
|
||||
|
||||
builder.mixin(core.class.TypePersonId, core.class.Class, view.mixin.AttributeEditor, {
|
||||
inlineEditor: view.component.PersonIdPresenter
|
||||
})
|
||||
|
||||
builder.mixin(core.class.TypePersonId, core.class.Class, view.mixin.AttributePresenter, {
|
||||
presenter: view.component.PersonIdPresenter,
|
||||
arrayPresenter: view.component.PersonArrayEditor
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
"@hcengineering/presentation": "workspace:^0.7.0",
|
||||
"@hcengineering/communication-types": "workspace:^0.7.12",
|
||||
"@hcengineering/communication-resources": "workspace:^0.7.0",
|
||||
"@hcengineering/activity": "workspace:^0.7.0",
|
||||
"@hcengineering/core": "workspace:^0.7.24",
|
||||
"@hcengineering/ui": "workspace:^0.7.0",
|
||||
"@hcengineering/setting": "workspace:^0.7.0",
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import cardPlugin, { type Card, type CardSection } from '@hcengineering/card'
|
||||
import { getResource } from '@hcengineering/platform'
|
||||
import { getMetadata, getResource } from '@hcengineering/platform'
|
||||
import { type Heading } from '@hcengineering/text-editor'
|
||||
import communication from '@hcengineering/communication'
|
||||
|
||||
@@ -69,12 +69,14 @@ export function getCardToc (sections: CardSection[], tocBySection: Record<string
|
||||
}
|
||||
}
|
||||
|
||||
newToc.push({
|
||||
id: communication.ids.CardMessagesSection,
|
||||
titleIntl: communication.string.Messages,
|
||||
level: 0,
|
||||
group: communication.ids.CardMessagesSection
|
||||
})
|
||||
if (getMetadata(communication.metadata.Enabled) === true) {
|
||||
newToc.push({
|
||||
id: communication.ids.CardMessagesSection,
|
||||
titleIntl: communication.string.Messages,
|
||||
level: 0,
|
||||
group: communication.ids.CardMessagesSection
|
||||
})
|
||||
}
|
||||
|
||||
return newToc
|
||||
}
|
||||
|
||||
@@ -17,11 +17,11 @@
|
||||
import { PermissionsStore } from '@hcengineering/contact'
|
||||
import { permissionsStore } from '@hcengineering/contact-resources'
|
||||
import core, { AnyAttribute, Class, Doc, Ref, toRank, TypedSpace } from '@hcengineering/core'
|
||||
import notification from '@hcengineering/notification'
|
||||
import {
|
||||
AttributeBarEditor,
|
||||
createQuery,
|
||||
getClient,
|
||||
getFiltredKeys,
|
||||
isCollectionAttr,
|
||||
KeyedAttribute
|
||||
} from '@hcengineering/presentation'
|
||||
@@ -29,11 +29,12 @@
|
||||
|
||||
export let object: Card
|
||||
export let _class: Ref<Class<Doc>>
|
||||
export let to: Ref<Class<Doc>> | undefined = core.class.Doc
|
||||
export let to: Ref<Class<Doc>> | undefined = core.class.Obj
|
||||
export let ignoreKeys: string[] = []
|
||||
export let readonly = false
|
||||
export let showHeader: boolean = true
|
||||
export let fourRows: boolean = false
|
||||
export let showCollaborators: boolean = false
|
||||
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
@@ -41,14 +42,18 @@
|
||||
let keys: KeyedAttribute[] = []
|
||||
|
||||
function updateKeys (_class: Ref<Class<Doc>>, ignoreKeys: string[], to: Ref<Class<Doc>> | undefined): void {
|
||||
const filtredKeys = getFiltredKeys(hierarchy, _class, ignoreKeys, to)
|
||||
keys = filtredKeys
|
||||
.filter((key) => !isCollectionAttr(hierarchy, key))
|
||||
.sort((a, b) => {
|
||||
const rankA = a.attr.rank ?? toRank(a.attr._id) ?? ''
|
||||
const rankB = b.attr.rank ?? toRank(b.attr._id) ?? ''
|
||||
return rankA.localeCompare(rankB)
|
||||
})
|
||||
const filtredKeys = [...hierarchy.getAllAttributes(_class, to).entries()]
|
||||
.filter(
|
||||
([key, value]) =>
|
||||
value.hidden !== true && !ignoreKeys.includes(key) && !isCollectionAttr(hierarchy, { key, attr: value })
|
||||
)
|
||||
.map(([key, attr]) => ({ key, attr }))
|
||||
|
||||
keys = filtredKeys.sort((a, b) => {
|
||||
const rankA = a.attr.rank ?? toRank(a.attr._id) ?? ''
|
||||
const rankB = b.attr.rank ?? toRank(b.attr._id) ?? ''
|
||||
return rankA.localeCompare(rankB)
|
||||
})
|
||||
}
|
||||
|
||||
$: updateKeys(_class, ignoreKeys, to)
|
||||
@@ -75,6 +80,17 @@
|
||||
on:update
|
||||
/>
|
||||
{/each}
|
||||
{#if showCollaborators}
|
||||
<AttributeBarEditor
|
||||
key={'collaborators'}
|
||||
_class={notification.mixin.Collaborators}
|
||||
{object}
|
||||
{showHeader}
|
||||
{readonly}
|
||||
withIcon
|
||||
on:update
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
@@ -15,15 +15,12 @@
|
||||
//
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Analytics } from '@hcengineering/analytics'
|
||||
import { Card, CardEvents } from '@hcengineering/card'
|
||||
import { Ref } from '@hcengineering/core'
|
||||
import { onMount } from 'svelte'
|
||||
import { Analytics } from '@hcengineering/analytics'
|
||||
import communication from '@hcengineering/communication'
|
||||
import { getMetadata } from '@hcengineering/platform'
|
||||
|
||||
import EditCardNew from './EditCardNew.svelte'
|
||||
import EditCardOld from './EditCardOld.svelte'
|
||||
|
||||
export let _id: Ref<Card>
|
||||
export let readonly: boolean = false
|
||||
@@ -39,8 +36,4 @@
|
||||
})
|
||||
</script>
|
||||
|
||||
{#if getMetadata(communication.metadata.Enabled) === true}
|
||||
<EditCardNew {_id} {readonly} {embedded} {allowClose} on:close on:open />
|
||||
{:else}
|
||||
<EditCardOld {_id} {readonly} {embedded} on:close on:open />
|
||||
{/if}
|
||||
<EditCardNew {_id} {readonly} {embedded} {allowClose} on:close on:open />
|
||||
|
||||
@@ -15,12 +15,14 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { Card } from '@hcengineering/card'
|
||||
import { resizeObserver } from '@hcengineering/ui'
|
||||
import communication from '@hcengineering/communication'
|
||||
import { NotificationContext } from '@hcengineering/communication-types'
|
||||
import { Ref } from '@hcengineering/core'
|
||||
import { resizeObserver } from '@hcengineering/ui'
|
||||
|
||||
import EditCardTableOfContents from './EditCardTableOfContents.svelte'
|
||||
import { MessageInput } from '@hcengineering/communication-resources'
|
||||
import { getMetadata } from '@hcengineering/platform'
|
||||
import EditCardTableOfContents from './EditCardTableOfContents.svelte'
|
||||
|
||||
export let _id: Ref<Card>
|
||||
export let doc: Card
|
||||
@@ -55,7 +57,7 @@
|
||||
<EditCardTableOfContents bind:this={content} bind:scrollDiv {doc} {readonly} {context} {isContextLoaded} />
|
||||
{/key}
|
||||
{/if}
|
||||
{#if !readonly}
|
||||
{#if !readonly && getMetadata(communication.metadata.Enabled) === true}
|
||||
<div class="message-input" use:resizeObserver={onInputResize}>
|
||||
<MessageInput
|
||||
card={doc}
|
||||
|
||||
@@ -1,238 +0,0 @@
|
||||
<!--
|
||||
//
|
||||
// Copyright © 2025 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 { Attachments } from '@hcengineering/attachment-resources'
|
||||
import { Card } from '@hcengineering/card'
|
||||
import { Doc, Mixin, Ref, WithLookup } from '@hcengineering/core'
|
||||
import notification from '@hcengineering/notification'
|
||||
import { Panel } from '@hcengineering/panel'
|
||||
import { getResource } from '@hcengineering/platform'
|
||||
import { ComponentExtensions, createQuery, getClient } from '@hcengineering/presentation'
|
||||
import {
|
||||
Button,
|
||||
EditBox,
|
||||
FocusHandler,
|
||||
IconMoreH,
|
||||
createFocusManager,
|
||||
getCurrentLocation,
|
||||
navigate
|
||||
} from '@hcengineering/ui'
|
||||
import view from '@hcengineering/view'
|
||||
import {
|
||||
ParentsNavigator,
|
||||
RelationsEditor,
|
||||
canChangeDoc,
|
||||
getDocMixins,
|
||||
showMenu
|
||||
} from '@hcengineering/view-resources'
|
||||
import { createEventDispatcher, onDestroy } from 'svelte'
|
||||
|
||||
import card from '../plugin'
|
||||
import CardAttributeEditor from './CardAttributeEditor.svelte'
|
||||
import CardIcon from './CardIcon.svelte'
|
||||
import CardPresenter from './CardPresenter.svelte'
|
||||
import Childs from './Childs.svelte'
|
||||
import Content from './Content.svelte'
|
||||
import TagsEditor from './TagsEditor.svelte'
|
||||
import { permissionsStore } from '@hcengineering/contact-resources'
|
||||
import CardVersionSelector from './CardVersionSelector.svelte'
|
||||
|
||||
export let _id: Ref<Card>
|
||||
export let readonly: boolean = false
|
||||
export let embedded: boolean = false
|
||||
|
||||
let useMaxWidth = getUseMaxWidth()
|
||||
$: saveUseMaxWidth(useMaxWidth)
|
||||
|
||||
let lastId: Ref<Doc> = _id
|
||||
const query = createQuery()
|
||||
const dispatch = createEventDispatcher()
|
||||
const client = getClient()
|
||||
|
||||
let doc: WithLookup<Card> | undefined
|
||||
let title = ''
|
||||
let innerWidth: number
|
||||
|
||||
const notificationClient = getResource(notification.function.GetInboxNotificationsClient).then((res) => res())
|
||||
|
||||
$: read(_id)
|
||||
function read (_id: Ref<Doc>): void {
|
||||
if (lastId !== _id) {
|
||||
const prev = lastId
|
||||
lastId = _id
|
||||
void notificationClient.then((client) => client.readDoc(prev))
|
||||
}
|
||||
}
|
||||
|
||||
onDestroy(async () => {
|
||||
void notificationClient.then((client) => client.readDoc(_id))
|
||||
})
|
||||
|
||||
$: _id !== undefined &&
|
||||
query.query(card.class.Card, { _id }, async (result) => {
|
||||
if (result.length > 0) {
|
||||
;[doc] = result
|
||||
title = doc?.title ?? ''
|
||||
} else {
|
||||
const loc = getCurrentLocation()
|
||||
loc.path.length = 3
|
||||
navigate(loc)
|
||||
}
|
||||
})
|
||||
|
||||
$: _readonly = (readonly || doc?.readonly) ?? false
|
||||
$: updatePermissionForbidden = doc && !canChangeDoc(doc?._class, doc?.space, $permissionsStore)
|
||||
$: canSave = title.trim().length > 0 && !_readonly
|
||||
|
||||
async function saveTitle (ev: Event): Promise<void> {
|
||||
ev.preventDefault()
|
||||
|
||||
if (doc === undefined || !canSave) {
|
||||
return
|
||||
}
|
||||
|
||||
const nameTrimmed = title.trim()
|
||||
|
||||
if (nameTrimmed.length > 0 && nameTrimmed !== doc.title) {
|
||||
await client.update(doc, { title: nameTrimmed })
|
||||
}
|
||||
}
|
||||
|
||||
function getUseMaxWidth (): boolean {
|
||||
const useMaxWidth = localStorage.getItem('document.useMaxWidth')
|
||||
return useMaxWidth === 'true'
|
||||
}
|
||||
|
||||
function saveUseMaxWidth (useMaxWidth: boolean): void {
|
||||
localStorage.setItem('document.useMaxWidth', useMaxWidth.toString())
|
||||
}
|
||||
|
||||
let content: HTMLElement
|
||||
|
||||
const manager = createFocusManager()
|
||||
|
||||
let mixins: Array<Mixin<Doc>> = []
|
||||
|
||||
$: mixins = doc !== undefined ? getDocMixins(doc) : []
|
||||
</script>
|
||||
|
||||
<FocusHandler {manager} />
|
||||
|
||||
{#if doc !== undefined}
|
||||
<Panel
|
||||
object={doc}
|
||||
allowClose={!embedded}
|
||||
isAside={false}
|
||||
isHeader={false}
|
||||
isSub={false}
|
||||
bind:useMaxWidth
|
||||
printHeader={false}
|
||||
{embedded}
|
||||
adaptive={'default'}
|
||||
bind:content
|
||||
bind:innerWidth
|
||||
floatAside={false}
|
||||
on:open
|
||||
on:close={() => dispatch('close')}
|
||||
>
|
||||
<svelte:fragment slot="beforeTitle">
|
||||
<CardIcon value={doc} />
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="title">
|
||||
<ParentsNavigator element={doc} />
|
||||
<CardPresenter value={doc} noUnderline />
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="extra">
|
||||
<ComponentExtensions
|
||||
extension={card.extensions.EditCardHeaderExtension}
|
||||
props={{
|
||||
card: doc
|
||||
}}
|
||||
/>
|
||||
<slot name="extra" />
|
||||
</svelte:fragment>
|
||||
|
||||
<div class="container">
|
||||
<div class="title flex-row-center">
|
||||
<EditBox
|
||||
focusIndex={1}
|
||||
bind:value={title}
|
||||
disabled={_readonly || updatePermissionForbidden}
|
||||
placeholder={card.string.Card}
|
||||
on:blur={(evt) => saveTitle(evt)}
|
||||
shrink
|
||||
/>
|
||||
</div>
|
||||
|
||||
<CardVersionSelector bind:value={doc} />
|
||||
|
||||
<TagsEditor {doc} readonly={_readonly} />
|
||||
|
||||
<CardAttributeEditor value={doc} {mixins} readonly={_readonly} ignoreKeys={['title', 'content', 'parent']} />
|
||||
|
||||
<Content {doc} readonly={_readonly || updatePermissionForbidden} bind:content />
|
||||
</div>
|
||||
|
||||
<ComponentExtensions
|
||||
extension={card.extensions.EditCardExtension}
|
||||
props={{
|
||||
card: doc
|
||||
}}
|
||||
/>
|
||||
|
||||
<Childs object={doc} readonly={_readonly} />
|
||||
<RelationsEditor object={doc} readonly={_readonly} />
|
||||
|
||||
<Attachments
|
||||
objectId={doc._id}
|
||||
_class={doc._class}
|
||||
space={doc.space}
|
||||
readonly={_readonly}
|
||||
attachments={doc.attachments ?? 0}
|
||||
/>
|
||||
|
||||
<svelte:fragment slot="utils">
|
||||
{#if !_readonly}
|
||||
<Button
|
||||
icon={IconMoreH}
|
||||
iconProps={{ size: 'medium' }}
|
||||
kind={'icon'}
|
||||
dataId={'btnMoreActions'}
|
||||
on:click={(e) => {
|
||||
showMenu(e, { object: doc, excludedActions: [view.action.Open] })
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</Panel>
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
}
|
||||
.title {
|
||||
font-size: 2.25rem;
|
||||
margin-top: 1.75rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
</style>
|
||||
@@ -15,18 +15,18 @@
|
||||
|
||||
<script lang="ts">
|
||||
import card, { Card, CardSection, CardViewDefaults } from '@hcengineering/card'
|
||||
import { Component, Loading, Scroller, ModernButton } from '@hcengineering/ui'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import communication from '@hcengineering/communication'
|
||||
import { NotificationContext } from '@hcengineering/communication-types'
|
||||
import { Ref } from '@hcengineering/core'
|
||||
import { SvelteComponent, tick } from 'svelte'
|
||||
import { TableOfContents } from '@hcengineering/text-editor-resources'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { Heading } from '@hcengineering/text-editor'
|
||||
import communication from '@hcengineering/communication'
|
||||
import { MessagesSection } from '@hcengineering/communication-resources'
|
||||
import { TableOfContents } from '@hcengineering/text-editor-resources'
|
||||
import { Component, Loading, ModernButton, Scroller } from '@hcengineering/ui'
|
||||
import { SvelteComponent, tick } from 'svelte'
|
||||
|
||||
import { CardSectionAction } from '../types'
|
||||
import { getMetadata } from '@hcengineering/platform'
|
||||
import { getCardSections, getCardToc } from '../card'
|
||||
import { CardSectionAction } from '../types'
|
||||
|
||||
export let doc: Card
|
||||
export let context: NotificationContext | undefined = undefined
|
||||
@@ -216,6 +216,12 @@
|
||||
|
||||
$: updateToc(sections, subTocBySection)
|
||||
$: showOverlay = !isScrollInitialized || Object.values(sectionOverlays).some((it) => it)
|
||||
|
||||
const onRenderTopChange = (active: boolean): void => {
|
||||
renderTopSections = active
|
||||
}
|
||||
|
||||
const bottomPadding = getMetadata(communication.metadata.Enabled) === true ? 'var(--spacing-3)' : undefined
|
||||
</script>
|
||||
|
||||
<div class="hulyComponent-content__container columns relative">
|
||||
@@ -240,7 +246,7 @@
|
||||
<Scroller
|
||||
padding="0"
|
||||
{hideBar}
|
||||
bottomPadding="var(--spacing-3)"
|
||||
{bottomPadding}
|
||||
disablePointerEventsOnScroll
|
||||
disableOverscroll
|
||||
bind:divScroll={scrollDiv}
|
||||
@@ -259,7 +265,12 @@
|
||||
scrollDiv,
|
||||
contentDiv: sectionElement[section._id],
|
||||
navigation: selectedToc?.id,
|
||||
hidden: !renderTopSections
|
||||
hidden: !renderTopSections,
|
||||
isDefault: defaults?.defaultSection === section._id,
|
||||
active: selectedToc?.group === section._id,
|
||||
context,
|
||||
isContextLoaded,
|
||||
onRenderTopChange
|
||||
}}
|
||||
on:loaded={() => {
|
||||
handleSectionLoaded(section._id)
|
||||
@@ -273,34 +284,6 @@
|
||||
/>
|
||||
</div>
|
||||
{/each}
|
||||
<div id={messagesId} bind:this={sectionElement[messagesId]} class="section">
|
||||
<MessagesSection
|
||||
bind:this={sectionRef[messagesId]}
|
||||
{doc}
|
||||
{readonly}
|
||||
{isContextLoaded}
|
||||
{scrollDiv}
|
||||
{context}
|
||||
contentDiv={sectionElement[messagesId]}
|
||||
active={selectedToc?.group === messagesId}
|
||||
isDefault={defaults?.defaultSection === messagesId}
|
||||
on:top-loaded={() => {
|
||||
renderTopSections = true
|
||||
}}
|
||||
on:top-hidden={() => {
|
||||
renderTopSections = false
|
||||
}}
|
||||
on:loaded={() => {
|
||||
handleSectionLoaded(messagesId)
|
||||
}}
|
||||
on:change={(ev) => {
|
||||
handleChangeNavigation(messagesId, ev.detail)
|
||||
}}
|
||||
on:action={(ev) => {
|
||||
handleAction(messagesId, ev.detail)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Scroller>
|
||||
{#if toc.length > 0 && (bottomOffset > 400 || canScrollDown()) && selectedToc?.group === messagesId}
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
{/if}
|
||||
</div>
|
||||
<ExpandCollapse isExpanded={!isCollapsed}>
|
||||
<CardAttributes object={value} _class={value._class} {readonly} {ignoreKeys} {fourRows} />
|
||||
<CardAttributes object={value} _class={value._class} {readonly} {ignoreKeys} {fourRows} showCollaborators />
|
||||
</ExpandCollapse>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
@@ -38,8 +38,8 @@
|
||||
export let ignoreKeys: string[]
|
||||
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
const label = hierarchy.getClass(tag._id).label
|
||||
const h = client.getHierarchy()
|
||||
const label = h.getClass(tag._id).label
|
||||
|
||||
let isCollapsed = false
|
||||
|
||||
@@ -52,6 +52,8 @@
|
||||
}
|
||||
|
||||
$: color = getPlatformColorDef(tag.background ?? 0, $themeStore.dark).color
|
||||
|
||||
$: isEditable = h.hasMixin(tag, setting.mixin.Editable) && h.as(tag, setting.mixin.Editable).value
|
||||
</script>
|
||||
|
||||
<div class="header flex flex-gap-2">
|
||||
@@ -66,7 +68,7 @@
|
||||
</span>
|
||||
<Chevron expanded={!isCollapsed} outline fill={'var(--content-color'} />
|
||||
</div>
|
||||
{#if hasAccountRole(getCurrentAccount(), AccountRole.Maintainer)}
|
||||
{#if hasAccountRole(getCurrentAccount(), AccountRole.Maintainer) && isEditable}
|
||||
<div class="btns">
|
||||
<Button
|
||||
icon={IconAdd}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
<!--
|
||||
// Copyright © 2026 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 { Card } from '@hcengineering/card'
|
||||
import { MessagesSection } from '@hcengineering/communication-resources'
|
||||
import { NotificationContext } from '@hcengineering/communication-types'
|
||||
|
||||
export let doc: Card
|
||||
export let readonly: boolean = false
|
||||
export let scrollDiv: HTMLDivElement | undefined | null = undefined
|
||||
export let context: NotificationContext | undefined = undefined
|
||||
export let contentDiv: HTMLDivElement
|
||||
export let isContextLoaded: boolean = false
|
||||
export let active: boolean = false
|
||||
export let isDefault: boolean = false
|
||||
export let onRenderTopChange: (active: boolean) => void
|
||||
</script>
|
||||
|
||||
<MessagesSection
|
||||
{doc}
|
||||
{readonly}
|
||||
{isContextLoaded}
|
||||
{scrollDiv}
|
||||
{context}
|
||||
{contentDiv}
|
||||
{active}
|
||||
{isDefault}
|
||||
on:top-loaded={() => {
|
||||
onRenderTopChange(true)
|
||||
}}
|
||||
on:top-hidden={() => {
|
||||
onRenderTopChange(false)
|
||||
}}
|
||||
on:loaded
|
||||
on:change
|
||||
on:action
|
||||
/>
|
||||
@@ -0,0 +1,36 @@
|
||||
<!--
|
||||
// Copyright © 2026 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 { Component } from '@hcengineering/ui'
|
||||
import activity from '@hcengineering/activity'
|
||||
import { Card } from '@hcengineering/card'
|
||||
|
||||
export let doc: Card
|
||||
export let readonly: boolean = false
|
||||
export let contentDiv: HTMLDivElement
|
||||
</script>
|
||||
|
||||
<div class="flex-col w-full px-4">
|
||||
<Component
|
||||
is={activity.component.Activity}
|
||||
props={{
|
||||
object: doc,
|
||||
showCommenInput: !readonly,
|
||||
focusIndex: 1000,
|
||||
boundary: contentDiv
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
@@ -20,6 +20,7 @@
|
||||
Class,
|
||||
ClassPermission,
|
||||
Doc,
|
||||
notEmpty,
|
||||
Permission,
|
||||
Ref
|
||||
} from '@hcengineering/core'
|
||||
@@ -58,7 +59,8 @@
|
||||
.getModel()
|
||||
.findAllSync(cardPlugin.class.PermissionObjectClass, {})
|
||||
.map((poc) => poc.objectClass)
|
||||
const tagDesc = Array.from(new Set(role?.types?.map((p) => [...h.getAncestors(p), ...h.getDescendants(p)]).flat()))
|
||||
const types = role?.types?.map((p) => h.findClass(p)).filter(notEmpty)
|
||||
const tagDesc = Array.from(new Set(types?.map((p) => [...h.getAncestors(p._id), ...h.getDescendants(p._id)]).flat()))
|
||||
const allPermissions = client.getModel().findAllSync(core.class.Permission, {
|
||||
scope: 'space',
|
||||
objectClass: { $in: [...cardPermissionsObjectClasses, ...tagDesc] }
|
||||
|
||||
@@ -14,18 +14,17 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { MasterTag } from '@hcengineering/card'
|
||||
import { ClassPermission, Ref } from '@hcengineering/core'
|
||||
import { getClient, MessageBox } from '@hcengineering/presentation'
|
||||
import { ClassAttributes } from '@hcengineering/setting-resources'
|
||||
import setting from '@hcengineering/setting-resources/src/plugin'
|
||||
import { ButtonIcon, showPopup } from '@hcengineering/ui'
|
||||
import card from '../../plugin'
|
||||
import { getClient, MessageBox } from '@hcengineering/presentation'
|
||||
import core, { ClassPermission, Ref } from '@hcengineering/core'
|
||||
import view from '@hcengineering/view'
|
||||
import { createTypePermissions } from '../../utils'
|
||||
|
||||
export let masterTag: MasterTag
|
||||
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
|
||||
let isRestricted: boolean =
|
||||
client.getModel().findObject(getPermissionRef(false)) !== undefined ||
|
||||
@@ -43,43 +42,7 @@
|
||||
message: setting.string.RestrictedAttributeWarning,
|
||||
action: async () => {
|
||||
isRestricted = true
|
||||
const isMixin = hierarchy.isMixin(masterTag._id)
|
||||
const objectClass = hierarchy.getBaseClass(masterTag._id)
|
||||
const txClass = isMixin ? core.class.TxMixin : core.class.TxUpdateDoc
|
||||
await client.createDoc(
|
||||
core.class.ClassPermission,
|
||||
core.space.Model,
|
||||
{
|
||||
objectClass,
|
||||
txClass,
|
||||
txMatch: {
|
||||
[isMixin ? 'mixin' : 'objectClass']: masterTag._id
|
||||
},
|
||||
scope: 'space',
|
||||
forbid: false,
|
||||
label: view.string.AllowAttributeChanges,
|
||||
description: masterTag.label,
|
||||
targetClass: masterTag._id
|
||||
},
|
||||
getPermissionRef(false)
|
||||
)
|
||||
await client.createDoc(
|
||||
core.class.ClassPermission,
|
||||
core.space.Model,
|
||||
{
|
||||
objectClass,
|
||||
txClass,
|
||||
txMatch: {
|
||||
[isMixin ? 'mixin' : 'objectClass']: masterTag._id
|
||||
},
|
||||
scope: 'space',
|
||||
forbid: true,
|
||||
label: view.string.ForbidAttributeChanges,
|
||||
description: masterTag.label,
|
||||
targetClass: masterTag._id
|
||||
},
|
||||
getPermissionRef(true)
|
||||
)
|
||||
await createTypePermissions(masterTag)
|
||||
}
|
||||
},
|
||||
'top',
|
||||
|
||||
@@ -128,11 +128,22 @@ async function exportType (_id: Ref<Class<Doc>>, processed: Set<Ref<Doc>>): Prom
|
||||
const m = client.getModel()
|
||||
const h = client.getHierarchy()
|
||||
const type = m.findObject(_id)
|
||||
|
||||
const parent = h.getClass(_id).extends
|
||||
if (parent !== undefined && h.isDerived(parent, card.class.Card) && parent !== card.class.Card) {
|
||||
if (!processed.has(parent)) {
|
||||
res.push(...(await exportType(parent, processed)))
|
||||
}
|
||||
}
|
||||
|
||||
processed.add(_id)
|
||||
if (type === undefined) return res
|
||||
if (type.icon === view.ids.IconWithEmoji && typeof type.color === 'string') {
|
||||
type.icon = card.icon.Card
|
||||
}
|
||||
|
||||
res.push(...m.findAllSync(view.class.Viewlet, { attachTo: _id }))
|
||||
|
||||
res.push(type)
|
||||
|
||||
res.push(...m.findAllSync(core.class.ClassPermission, { targetClass: _id }))
|
||||
@@ -152,8 +163,6 @@ async function exportType (_id: Ref<Class<Doc>>, processed: Set<Ref<Doc>>): Prom
|
||||
|
||||
res.push(...m.findAllSync(card.class.Role, { types: _id }))
|
||||
|
||||
res.push(...m.findAllSync(view.class.Viewlet, { attachTo: _id }))
|
||||
|
||||
const assocA = m.findAllSync(core.class.Association, { classA: _id })
|
||||
for (const assoc of assocA) {
|
||||
res.push(assoc)
|
||||
@@ -174,13 +183,6 @@ async function exportType (_id: Ref<Class<Doc>>, processed: Set<Ref<Doc>>): Prom
|
||||
required.push(...extRes.required)
|
||||
}
|
||||
|
||||
const parent = h.getClass(_id).extends
|
||||
if (parent !== undefined && h.isDerived(parent, card.class.Card) && parent !== card.class.Card) {
|
||||
if (!processed.has(parent)) {
|
||||
required.push(parent)
|
||||
}
|
||||
}
|
||||
|
||||
for (const req of required) {
|
||||
res.push(...(await exportType(req, processed)))
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ import {
|
||||
cardCustomLinkMatch,
|
||||
openCardInSidebar,
|
||||
checkRelationsSectionVisibility,
|
||||
checkOldMessagesSectionVisibility,
|
||||
checkCommunicationMessagesSectionVisibility,
|
||||
getSpaceAccessPublicLink,
|
||||
canGetSpaceAccessPublicLink,
|
||||
cardFactory,
|
||||
@@ -68,6 +70,9 @@ import ChildrenCardSection from './components/sections/ChildrenSection.svelte'
|
||||
import ContentCardSection from './components/sections/ContentSection.svelte'
|
||||
import PropertiesCardSection from './components/sections/PropertiesSection.svelte'
|
||||
import RelationsCardSection from './components/sections/RelationsSection.svelte'
|
||||
import CardCommunicatiomMessages from './components/sections/CardCommunicatiomMessages.svelte'
|
||||
import OldMessagesCardSection from './components/sections/OldMessagesCardSection.svelte'
|
||||
|
||||
import FavoriteCardPresenter from './components/FavoriteCardPresenter.svelte'
|
||||
import CardTagsColored from './components/CardTagsColored.svelte'
|
||||
import CardTagColored from './components/CardTagColored.svelte'
|
||||
@@ -137,7 +142,9 @@ export default async (): Promise<Resources> => ({
|
||||
ChildrenSection: ChildrenCardSection,
|
||||
ContentSection: ContentCardSection,
|
||||
PropertiesSection: PropertiesCardSection,
|
||||
RelationsSection: RelationsCardSection
|
||||
RelationsSection: RelationsCardSection,
|
||||
OldMessagesSection: OldMessagesCardSection,
|
||||
CommunicationMessagesSection: CardCommunicatiomMessages
|
||||
},
|
||||
completion: {
|
||||
CardQuery: queryCard
|
||||
@@ -158,6 +165,8 @@ export default async (): Promise<Resources> => ({
|
||||
CardCustomLinkEncode: cardCustomLinkEncode,
|
||||
OpenCardInSidebar: openCardInSidebar,
|
||||
CheckRelationsSectionVisibility: checkRelationsSectionVisibility,
|
||||
CheckOldMessagesSectionVisibility: checkOldMessagesSectionVisibility,
|
||||
CheckCommunicationMessagesSectionVisibility: checkCommunicationMessagesSectionVisibility,
|
||||
GetSpaceAccessPublicLink: getSpaceAccessPublicLink,
|
||||
CanGetSpaceAccessPublicLink: canGetSpaceAccessPublicLink,
|
||||
CardFactory: cardFactory
|
||||
|
||||
@@ -76,7 +76,9 @@ export default mergeIds(cardId, card, {
|
||||
ChildrenSection: '' as AnyComponent,
|
||||
ContentSection: '' as AnyComponent,
|
||||
PropertiesSection: '' as AnyComponent,
|
||||
RelationsSection: '' as AnyComponent
|
||||
RelationsSection: '' as AnyComponent,
|
||||
CommunicationMessagesSection: '' as AnyComponent,
|
||||
OldMessagesSection: '' as AnyComponent
|
||||
},
|
||||
completion: {
|
||||
CardQuery: '' as Resource<ObjectSearchFactory>,
|
||||
@@ -135,6 +137,26 @@ export default mergeIds(cardId, card, {
|
||||
EnableVersioning: '' as IntlString,
|
||||
EnableVersioningConfirm: '' as IntlString,
|
||||
NewVersionConfirmation: '' as IntlString,
|
||||
RelationCopyDescr: '' as IntlString
|
||||
RelationCopyDescr: '' as IntlString,
|
||||
CreateCardPersmissionDescription: '' as IntlString,
|
||||
UpdateCardPersmissionDescription: '' as IntlString,
|
||||
RemoveCardPersmissionDescription: '' as IntlString,
|
||||
AddTagPersmissionDescription: '' as IntlString,
|
||||
RemoveTagPersmissionDescription: '' as IntlString,
|
||||
RemoveCard: '' as IntlString,
|
||||
UpdateCard: '' as IntlString,
|
||||
CreateCardPermission: '' as IntlString,
|
||||
AddTagPermission: '' as IntlString,
|
||||
RemoveTag: '' as IntlString,
|
||||
ForbidCreateCardPersmissionDescription: '' as IntlString,
|
||||
ForbidUpdateCardPersmissionDescription: '' as IntlString,
|
||||
ForbidRemoveCardPersmissionDescription: '' as IntlString,
|
||||
ForbidAddTagPersmissionDescription: '' as IntlString,
|
||||
ForbidRemoveTagPersmissionDescription: '' as IntlString,
|
||||
ForbidRemoveCard: '' as IntlString,
|
||||
ForbidUpdateCard: '' as IntlString,
|
||||
ForbidCreateCardPermission: '' as IntlString,
|
||||
ForbidAddTagPermission: '' as IntlString,
|
||||
ForbidRemoveTag: '' as IntlString
|
||||
}
|
||||
})
|
||||
|
||||
@@ -13,10 +13,12 @@
|
||||
|
||||
import { type AccountClient, getClient as getAccountClientRaw } from '@hcengineering/account-client'
|
||||
import { Analytics } from '@hcengineering/analytics'
|
||||
import { type Card, CardEvents, cardId, type CardSpace, type MasterTag } from '@hcengineering/card'
|
||||
import communication from '@hcengineering/communication'
|
||||
import { type Card, CardEvents, cardId, type CardSpace, type MasterTag, type Tag } from '@hcengineering/card'
|
||||
import core, {
|
||||
AccountRole,
|
||||
type Class,
|
||||
type ClassPermission,
|
||||
type Client,
|
||||
type Data,
|
||||
type Doc,
|
||||
@@ -97,6 +99,183 @@ export async function deleteMasterTag (tag: MasterTag | undefined, onDelete?: ()
|
||||
}
|
||||
}
|
||||
|
||||
export async function createTypePermissions (masterTag: MasterTag | Tag): Promise<void> {
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
const isMixin = hierarchy.isMixin(masterTag._id)
|
||||
const objectClass = hierarchy.getBaseClass(masterTag._id)
|
||||
const txClass = isMixin ? core.class.TxMixin : core.class.TxUpdateDoc
|
||||
|
||||
await client.createDoc(
|
||||
core.class.ClassPermission,
|
||||
core.space.Model,
|
||||
{
|
||||
objectClass,
|
||||
txClass,
|
||||
txMatch: {
|
||||
[isMixin ? 'mixin' : 'objectClass']: masterTag._id
|
||||
},
|
||||
scope: 'space',
|
||||
forbid: false,
|
||||
label: view.string.AllowAttributeChanges,
|
||||
description: masterTag.label,
|
||||
targetClass: masterTag._id
|
||||
},
|
||||
`${masterTag._id}_allowed` as Ref<ClassPermission>
|
||||
)
|
||||
await client.createDoc(
|
||||
core.class.ClassPermission,
|
||||
core.space.Model,
|
||||
{
|
||||
objectClass,
|
||||
txClass,
|
||||
txMatch: {
|
||||
[isMixin ? 'mixin' : 'objectClass']: masterTag._id
|
||||
},
|
||||
scope: 'space',
|
||||
forbid: true,
|
||||
label: view.string.ForbidAttributeChanges,
|
||||
description: masterTag.label,
|
||||
targetClass: masterTag._id
|
||||
},
|
||||
`${masterTag._id}_forbidden` as Ref<ClassPermission>
|
||||
)
|
||||
|
||||
if (isMixin) {
|
||||
await client.createDoc(
|
||||
core.class.ClassPermission,
|
||||
core.space.Model,
|
||||
{
|
||||
objectClass,
|
||||
txClass: core.class.TxMixin,
|
||||
txMatch: {
|
||||
mixin: masterTag._id
|
||||
},
|
||||
scope: 'space',
|
||||
forbid: false,
|
||||
label: card.string.AddTagPermission,
|
||||
description: masterTag.label,
|
||||
targetClass: masterTag._id
|
||||
},
|
||||
`${masterTag._id}_create_allowed` as Ref<ClassPermission>
|
||||
)
|
||||
await client.createDoc(
|
||||
core.class.ClassPermission,
|
||||
core.space.Model,
|
||||
{
|
||||
objectClass,
|
||||
txClass: core.class.TxMixin,
|
||||
txMatch: {
|
||||
mixin: masterTag._id
|
||||
},
|
||||
scope: 'space',
|
||||
forbid: true,
|
||||
label: card.string.ForbidAddTagPermission,
|
||||
description: masterTag.label,
|
||||
targetClass: masterTag._id
|
||||
},
|
||||
`${masterTag._id}_create_forbidden` as Ref<ClassPermission>
|
||||
)
|
||||
const key = `operations.$unset.${masterTag._id}`
|
||||
await client.createDoc(
|
||||
core.class.ClassPermission,
|
||||
core.space.Model,
|
||||
{
|
||||
objectClass,
|
||||
txClass: core.class.TxUpdateDoc,
|
||||
txMatch: {
|
||||
[key]: {
|
||||
$exists: true
|
||||
}
|
||||
},
|
||||
scope: 'space',
|
||||
forbid: false,
|
||||
label: card.string.RemoveTag,
|
||||
description: masterTag.label,
|
||||
targetClass: masterTag._id
|
||||
},
|
||||
`${masterTag._id}_remove_allowed` as Ref<ClassPermission>
|
||||
)
|
||||
await client.createDoc(
|
||||
core.class.ClassPermission,
|
||||
core.space.Model,
|
||||
{
|
||||
objectClass,
|
||||
txClass: core.class.TxUpdateDoc,
|
||||
txMatch: {
|
||||
[key]: { $exists: true }
|
||||
},
|
||||
scope: 'space',
|
||||
forbid: true,
|
||||
label: card.string.ForbidRemoveTag,
|
||||
description: masterTag.label,
|
||||
targetClass: masterTag._id
|
||||
},
|
||||
`${masterTag._id}_remove_forbidden` as Ref<ClassPermission>
|
||||
)
|
||||
} else {
|
||||
await client.createDoc(
|
||||
core.class.ClassPermission,
|
||||
core.space.Model,
|
||||
{
|
||||
objectClass,
|
||||
txClass: core.class.TxCreateDoc,
|
||||
scope: 'space',
|
||||
forbid: false,
|
||||
label: card.string.CreateCardPermission,
|
||||
description: masterTag.label,
|
||||
targetClass: masterTag._id
|
||||
},
|
||||
`${masterTag._id}_create_allowed` as Ref<ClassPermission>
|
||||
)
|
||||
await client.createDoc(
|
||||
core.class.ClassPermission,
|
||||
core.space.Model,
|
||||
{
|
||||
objectClass,
|
||||
txClass: core.class.TxCreateDoc,
|
||||
scope: 'space',
|
||||
forbid: true,
|
||||
label: card.string.ForbidCreateCardPermission,
|
||||
description: masterTag.label,
|
||||
targetClass: masterTag._id
|
||||
},
|
||||
`${masterTag._id}_create_forbidden` as Ref<ClassPermission>
|
||||
)
|
||||
await client.createDoc(
|
||||
core.class.ClassPermission,
|
||||
core.space.Model,
|
||||
{
|
||||
objectClass,
|
||||
txClass: core.class.TxRemoveDoc,
|
||||
scope: 'space',
|
||||
forbid: false,
|
||||
label: card.string.RemoveCard,
|
||||
description: masterTag.label,
|
||||
targetClass: masterTag._id
|
||||
},
|
||||
`${masterTag._id}_remove_allowed` as Ref<ClassPermission>
|
||||
)
|
||||
await client.createDoc(
|
||||
core.class.ClassPermission,
|
||||
core.space.Model,
|
||||
{
|
||||
objectClass,
|
||||
txClass: core.class.TxRemoveDoc,
|
||||
txMatch: {
|
||||
objectClass: masterTag._id
|
||||
},
|
||||
scope: 'space',
|
||||
forbid: true,
|
||||
label: card.string.ForbidRemoveCard,
|
||||
description: masterTag.label,
|
||||
targetClass: masterTag._id
|
||||
},
|
||||
`${masterTag._id}_remove_forbidden` as Ref<ClassPermission>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async function cloneCard (
|
||||
origin: Card,
|
||||
overrideProps: Record<string, any>,
|
||||
@@ -437,6 +616,14 @@ export function cardCustomLinkEncode (doc: Card): Location {
|
||||
return loc
|
||||
}
|
||||
|
||||
export async function checkOldMessagesSectionVisibility (doc: Card): Promise<boolean> {
|
||||
return getMetadata(communication.metadata.Enabled) !== true
|
||||
}
|
||||
|
||||
export async function checkCommunicationMessagesSectionVisibility (doc: Card): Promise<boolean> {
|
||||
return getMetadata(communication.metadata.Enabled) === true
|
||||
}
|
||||
|
||||
export async function checkRelationsSectionVisibility (doc: Card): Promise<boolean> {
|
||||
const client = getClient()
|
||||
const h = client.getHierarchy()
|
||||
|
||||
@@ -211,7 +211,9 @@ const cardPlugin = plugin(cardId, {
|
||||
Children: '' as Ref<CardSection>,
|
||||
Content: '' as Ref<CardSection>,
|
||||
Properties: '' as Ref<CardSection>,
|
||||
Relations: '' as Ref<CardSection>
|
||||
Relations: '' as Ref<CardSection>,
|
||||
OldMessages: '' as Ref<CardSection>,
|
||||
CommunicationMessages: '' as Ref<CardSection>
|
||||
},
|
||||
ids: {
|
||||
CardWidget: '' as Ref<Doc>
|
||||
|
||||
@@ -218,7 +218,13 @@ export class ProjectDocumentTree {
|
||||
bundles.sort((a, b) => {
|
||||
const rankA = a.ProjectMeta[0]?.rank ?? ''
|
||||
const rankB = b.ProjectMeta[0]?.rank ?? ''
|
||||
return rankA.localeCompare(rankB)
|
||||
if (rankA !== rankB) {
|
||||
return rankA.localeCompare(rankB)
|
||||
} else {
|
||||
const titleA = a.DocumentMeta[0]?.title ?? ''
|
||||
const titleB = b.DocumentMeta[0]?.title ?? ''
|
||||
return titleA.localeCompare(titleB)
|
||||
}
|
||||
})
|
||||
|
||||
for (const bundle of bundles) {
|
||||
|
||||
@@ -12,18 +12,18 @@
|
||||
// limitations under the License.
|
||||
|
||||
import { type Resources } from '@hcengineering/platform'
|
||||
import ExecutionContextSelector from './components/attributeEditors/ExecutionContextSelector.svelte'
|
||||
import FunctionSelector from './components/attributeEditors/FunctionSelector.svelte'
|
||||
import NestedContextSelector from './components/attributeEditors/NestedContextSelector.svelte'
|
||||
import RelatedContextSelector from './components/attributeEditors/RelatedContextSelector.svelte'
|
||||
import ExecutionContextSelector from './components/attributeEditors/ExecutionContextSelector.svelte'
|
||||
import RequestUserInput from './components/contextEditors/RequestUserInput.svelte'
|
||||
import ResultInput from './components/contextEditors/ResultInput.svelte'
|
||||
import RoleEditor from './components/contextEditors/RoleEditor.svelte'
|
||||
import ErrorPresenter from './components/ErrorPresenter.svelte'
|
||||
import ExecutionMyToDos from './components/ExecutionMyToDos.svelte'
|
||||
import ExecutonPresenter from './components/ExecutonPresenter.svelte'
|
||||
import ExecutonProgressPresenter from './components/ExecutonProgressPresenter.svelte'
|
||||
import Main from './components/Main.svelte'
|
||||
import ExecutionMyToDos from './components/ExecutionMyToDos.svelte'
|
||||
import SubProcessPresenter from './components/presenters/SubProcessPresenter.svelte'
|
||||
import ToDoPresenter from './components/presenters/ToDoPresenter.svelte'
|
||||
import UpdateCardPresenter from './components/presenters/UpdateCardPresenter.svelte'
|
||||
@@ -34,6 +34,7 @@ import ProcessPresenter from './components/ProcessPresenter.svelte'
|
||||
import RunProcessCardPopup from './components/RunProcessCardPopup.svelte'
|
||||
import RunProcessPopup from './components/RunProcessPopup.svelte'
|
||||
import ActionsPresenter from './components/settings/ActionsPresenter.svelte'
|
||||
import FunctionSubmenu from './components/settings/FunctionSubmenu.svelte'
|
||||
import ProcessEditor from './components/settings/ProcessEditor.svelte'
|
||||
import StatePresenter from './components/settings/StatePresenter.svelte'
|
||||
import SubProcessEditor from './components/settings/SubProcessEditor.svelte'
|
||||
@@ -44,11 +45,10 @@ import TransitionEditor from './components/settings/TransitionEditor.svelte'
|
||||
import TriggerPresenter from './components/settings/TriggerPresenter.svelte'
|
||||
import UpdateCardEditor from './components/settings/UpdateCardEditor.svelte'
|
||||
import ArrayElementEditor from './components/transformEditors/ArrayElementEditor.svelte'
|
||||
import MultiArrayElementEditor from './components/transformEditors/MultiArrayElementEditor.svelte'
|
||||
import DateOffsetEditor from './components/transformEditors/DateOffsetEditor.svelte'
|
||||
import NumberEditor from './components/transformEditors/NumberEditor.svelte'
|
||||
import FilterEditor from './components/transformEditors/FilterEditor.svelte'
|
||||
import FunctionSubmenu from './components/settings/FunctionSubmenu.svelte'
|
||||
import MultiArrayElementEditor from './components/transformEditors/MultiArrayElementEditor.svelte'
|
||||
import NumberEditor from './components/transformEditors/NumberEditor.svelte'
|
||||
|
||||
import ArraySizeCriteria from './components/criterias/ArraySizeCriteria.svelte'
|
||||
import BaseCriteria from './components/criterias/BaseCriteria.svelte'
|
||||
@@ -56,40 +56,41 @@ import RangeCriteria from './components/criterias/RangeCriteria.svelte'
|
||||
import LogActionPresenter from './components/LogActionPresenter.svelte'
|
||||
import NotifierExtension from './components/NotifierExtension.svelte'
|
||||
import AddRelationPresenter from './components/presenters/AddRelationPresenter.svelte'
|
||||
import AddTagPresenter from './components/presenters/AddTagPresenter.svelte'
|
||||
import CreateCardPresenter from './components/presenters/CreateCardPresenter.svelte'
|
||||
import ProcessesHeaderExtension from './components/ProcessesHeaderExtension.svelte'
|
||||
import AddRelationEditor from './components/settings/AddRelationEditor.svelte'
|
||||
import AddTagEditor from './components/settings/AddTagEditor.svelte'
|
||||
import AddTagPresenter from './components/presenters/AddTagPresenter.svelte'
|
||||
import CardUpdateEditor from './components/settings/CardUpdateEditor.svelte'
|
||||
import CardUpdatePresenter from './components/settings/CardUpdatePresenter.svelte'
|
||||
import CreateCardEditor from './components/settings/CreateCardEditor.svelte'
|
||||
import FieldChangesEditor from './components/settings/FieldChangesEditor.svelte'
|
||||
import SubProcessMatchEditor from './components/settings/SubProcessMatchEditor.svelte'
|
||||
import SubProcessMatchPresenter from './components/settings/SubProcessMatchPresenter.svelte'
|
||||
import TimeEditor from './components/settings/TimeEditor.svelte'
|
||||
import TimePresenter from './components/settings/TimePresenter.svelte'
|
||||
import ToDoSettingPresenter from './components/settings/ToDoPresenter.svelte'
|
||||
import TransitionRefPresenter from './components/settings/TransitionRefPresenter.svelte'
|
||||
import SubProcessMatchEditor from './components/settings/SubProcessMatchEditor.svelte'
|
||||
import SubProcessMatchPresenter from './components/settings/SubProcessMatchPresenter.svelte'
|
||||
import AppendEditor from './components/transformEditors/AppendEditor.svelte'
|
||||
import CutEditor from './components/transformEditors/CutEditor.svelte'
|
||||
import ReplaceEditor from './components/transformEditors/ReplaceEditor.svelte'
|
||||
import SplitEditor from './components/transformEditors/SplitEditor.svelte'
|
||||
import NumberPresenter from './components/transformPresenters/NumberPresenter.svelte'
|
||||
import RolePresenter from './components/transformPresenters/RolePresenter.svelte'
|
||||
import ProcessesHeaderExtension from './components/ProcessesHeaderExtension.svelte'
|
||||
import { exportProcess } from './exporter'
|
||||
import { ProcessMiddleware } from './middleware'
|
||||
import {
|
||||
checkProcessSectionVisibility,
|
||||
continueExecution,
|
||||
showDoneQuery,
|
||||
timeTransitionCheck,
|
||||
todoTranstionCheck,
|
||||
matchCardCheck,
|
||||
subProcessesDoneCheck,
|
||||
eventCheck,
|
||||
fieldChangesCheck,
|
||||
matchCardCheck,
|
||||
showDoneQuery,
|
||||
subProcessesDoneCheck,
|
||||
subProcessMatchCheck,
|
||||
eventCheck
|
||||
timeTransitionCheck,
|
||||
todoTranstionCheck
|
||||
} from './utils'
|
||||
import FieldChangesEditor from './components/settings/FieldChangesEditor.svelte'
|
||||
import { exportProcess } from './exporter'
|
||||
|
||||
export * from './query'
|
||||
|
||||
@@ -181,6 +182,7 @@ export default async (): Promise<Resources> => ({
|
||||
function: {
|
||||
ExportProcess: exportProcess,
|
||||
ShowDoneQuery: showDoneQuery,
|
||||
CheckProcessSectionVisibility: checkProcessSectionVisibility,
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
CreateMiddleware: ProcessMiddleware.create
|
||||
}
|
||||
|
||||
@@ -749,3 +749,10 @@ export function getMockAttribute (_class: Ref<Class<Doc>>, label: IntlString, ty
|
||||
label
|
||||
}
|
||||
}
|
||||
|
||||
export async function checkProcessSectionVisibility (doc: Card): Promise<boolean> {
|
||||
const client = getClient()
|
||||
const anc = client.getHierarchy().getAncestors(doc._class)
|
||||
const processes = client.getModel().findAllSync(process.class.Process, { masterTag: { $in: anc } })
|
||||
return processes.length > 0
|
||||
}
|
||||
|
||||
@@ -204,10 +204,10 @@ export interface UpdateCriteriaComponent extends Doc {
|
||||
props: Record<string, any>
|
||||
}
|
||||
|
||||
export * from './dslContext'
|
||||
export * from './errors'
|
||||
export * from './types'
|
||||
export * from './utils'
|
||||
export * from './dslContext'
|
||||
|
||||
export default plugin(processId, {
|
||||
class: {
|
||||
@@ -340,6 +340,7 @@ export default plugin(processId, {
|
||||
ExecutionInitiator: '' as Ref<ProcessFunction>,
|
||||
EmptyArray: '' as Ref<ProcessFunction>,
|
||||
CurrentDate: '' as Ref<ProcessFunction>,
|
||||
ExportProcess: '' as Resource<ExportFunc>
|
||||
ExportProcess: '' as Resource<ExportFunc>,
|
||||
CheckProcessSectionVisibility: '' as Resource<(doc: Card) => Promise<boolean>>
|
||||
}
|
||||
})
|
||||
|
||||
@@ -14,9 +14,18 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Person } from '@hcengineering/contact'
|
||||
import { type Class, type Doc, type DocumentQuery, type FindOptions, type Ref } from '@hcengineering/core'
|
||||
import {
|
||||
getObjectValue,
|
||||
type Class,
|
||||
type Doc,
|
||||
type DocumentQuery,
|
||||
type FindOptions,
|
||||
type Ref
|
||||
} from '@hcengineering/core'
|
||||
import type { IntlString } from '@hcengineering/platform'
|
||||
import presentation, { ObjectCreate, ObjectPopup } from '@hcengineering/presentation'
|
||||
import presentation, { getClient, ObjectCreate, ObjectPopup } from '@hcengineering/presentation'
|
||||
import { Component } from '@hcengineering/ui'
|
||||
import { findAttributePresenter } from '../utils'
|
||||
import ObjectPresenter from './ObjectPresenter.svelte'
|
||||
|
||||
export let _class: Ref<Class<Doc>>
|
||||
@@ -35,6 +44,8 @@
|
||||
export let searchField: string = 'name'
|
||||
export let docProps: Record<string, any> = {}
|
||||
export let groupBy = '_class'
|
||||
|
||||
const client = getClient()
|
||||
</script>
|
||||
|
||||
<ObjectPopup
|
||||
@@ -57,6 +68,14 @@
|
||||
on:close
|
||||
on:changeContent
|
||||
>
|
||||
<svelte:fragment slot="category" let:item={it}>
|
||||
{@const presenter = findAttributePresenter(client, it._class, groupBy)}
|
||||
{#if presenter}
|
||||
<div class="menu-group__header">
|
||||
<Component is={presenter} props={{ value: getObjectValue(groupBy, it) }} />
|
||||
</div>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="item" let:item={doc}>
|
||||
<div class="flex flex-grow overflow-label">
|
||||
<ObjectPresenter
|
||||
|
||||
@@ -262,7 +262,12 @@ async function OnMasterTagCreate (ctx: TxCreateDoc<MasterTag | Tag>[], control:
|
||||
attachTo: tag.extends,
|
||||
variant: { $exists: false }
|
||||
})
|
||||
const existingViewlets = await control.findAll(control.ctx, view.class.Viewlet, {
|
||||
attachTo: createTx.objectId,
|
||||
variant: { $exists: false }
|
||||
})
|
||||
for (const viewlet of viewlets) {
|
||||
if (existingViewlets.find((it) => it.descriptor === viewlet.descriptor) !== undefined) continue
|
||||
const base = extractObjectData(viewlet)
|
||||
res.push(
|
||||
control.txFactory.createTxCreateDoc(view.class.Viewlet, core.space.Model, {
|
||||
|
||||
@@ -311,14 +311,30 @@ export async function getDocCollaborators (
|
||||
control: TriggerControl
|
||||
): Promise<AccountUuid[]> {
|
||||
const collaborators = new Set<AccountUuid>()
|
||||
for (const field of mixin.fields) {
|
||||
const value = (doc as any)[field]
|
||||
const newCollaborators = await ctx.with('getKeyCollaborators', {}, (ctx) =>
|
||||
getKeyCollaborators(doc._class, value, field, control)
|
||||
)
|
||||
if (newCollaborators !== undefined) {
|
||||
for (const newCollaborator of newCollaborators) {
|
||||
collaborators.add(newCollaborator)
|
||||
if (mixin.allFields !== true) {
|
||||
for (const field of mixin.fields) {
|
||||
const value = (doc as any)[field]
|
||||
const newCollaborators = await ctx.with('getKeyCollaborators', {}, (ctx) =>
|
||||
getKeyCollaborators(doc._class, value, field, control)
|
||||
)
|
||||
if (newCollaborators !== undefined) {
|
||||
for (const newCollaborator of newCollaborators) {
|
||||
collaborators.add(newCollaborator)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const attrs = control.hierarchy.getAllAttributes(doc._class)
|
||||
// attr type will be checked into getKeyCollaborators
|
||||
for (const [field] of attrs) {
|
||||
const value = (doc as any)[field]
|
||||
const newCollaborators = await ctx.with('getKeyCollaborators', {}, (ctx) =>
|
||||
getKeyCollaborators(doc._class, value, field, control)
|
||||
)
|
||||
if (newCollaborators !== undefined) {
|
||||
for (const newCollaborator of newCollaborators) {
|
||||
collaborators.add(newCollaborator)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1137,7 +1153,7 @@ async function getNewCollaborators (
|
||||
const newCollaborators = new Set<AccountUuid>()
|
||||
if (ops.$push !== undefined) {
|
||||
for (const key in ops.$push) {
|
||||
if (mixin.fields.includes(key as any)) {
|
||||
if (mixin.fields.includes(key as any) || mixin.allFields === true) {
|
||||
let value = (ops.$push as any)[key]
|
||||
if (typeof value !== 'string') {
|
||||
value = value.$each
|
||||
@@ -1153,7 +1169,7 @@ async function getNewCollaborators (
|
||||
}
|
||||
for (const key in ops) {
|
||||
if (key.startsWith('$')) continue
|
||||
if (mixin.fields.includes(key as any)) {
|
||||
if (mixin.fields.includes(key as any) || mixin.allFields === true) {
|
||||
const value = (ops as any)[key]
|
||||
const newCollabs = await getKeyCollaborators(docClass, value, key, control)
|
||||
if (newCollabs !== undefined) {
|
||||
@@ -1176,7 +1192,7 @@ async function getRemovedMembers (
|
||||
const removedCollaborators: AccountUuid[] = []
|
||||
if (ops.$pull !== undefined && 'members' in ops.$pull) {
|
||||
const key = 'members'
|
||||
if (mixin.fields.includes(key as any)) {
|
||||
if (mixin.fields.includes(key as any) || mixin.allFields === true) {
|
||||
let value = (ops.$pull as any)[key]
|
||||
if (typeof value !== 'string') {
|
||||
value = value.$in
|
||||
|
||||
Reference in New Issue
Block a user