mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-27 12:04:56 +02:00
card RBAC (#10197)
Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
Vendored
+3
-2
@@ -97,7 +97,7 @@
|
||||
"MODEL_JSON": "${workspaceRoot}/models/all/bundle/model.json",
|
||||
// "SERVER_PROVIDER":"uweb"
|
||||
"SERVER_PROVIDER": "ws",
|
||||
"MODEL_VERSION": "0.7.278",
|
||||
"MODEL_VERSION": "0.7.301",
|
||||
// "version": "0.7.0",
|
||||
"COMMUNICATION_API_ENABLED": "true",
|
||||
"ELASTIC_INDEX_NAME": "local_storage_index",
|
||||
@@ -315,10 +315,11 @@
|
||||
"SERVER_SECRET": "secret",
|
||||
"TRANSACTOR_URL": "ws://localhost:3332",
|
||||
"ACCOUNTS_URL": "http://localhost:3000",
|
||||
"ACCOUNTS_DB_URL": "postgresql://root@huly.local:26257/defaultdb?sslmode=disable",
|
||||
"FRONT_URL": "http://localhost:8080",
|
||||
"MAIL_URL": "",
|
||||
"STORAGE_CONFIG": "datalake|http://localhost:4030",
|
||||
"MODEL_VERSION": "0.7.153",
|
||||
"MODEL_VERSION": "0.7.301",
|
||||
"WS_OPERATION": "all+backup",
|
||||
"BACKUP_STORAGE": "minio|minio?accessKey=minioadmin&secretKey=minioadmin",
|
||||
"BACKUP_BUCKET": "dev-backups",
|
||||
|
||||
Generated
+1892
-1885
File diff suppressed because it is too large
Load Diff
@@ -1 +1 @@
|
||||
"0.7.292"
|
||||
"0.7.301"
|
||||
|
||||
@@ -160,6 +160,7 @@ async function migrateChannel (
|
||||
autoJoin: doc.autoJoin,
|
||||
owners: doc.owners,
|
||||
types: [chat.masterTag.Thread],
|
||||
type: cardPlugin.spaceType.SpaceType,
|
||||
space: cardPlugin.space.Default,
|
||||
modifiedBy: doc.modifiedBy,
|
||||
modifiedOn: doc.modifiedOn,
|
||||
|
||||
+35
-12
@@ -26,6 +26,7 @@ import {
|
||||
type FavoriteType,
|
||||
type MasterTag,
|
||||
type ParentInfo,
|
||||
type PermissionObjectClass,
|
||||
type Role,
|
||||
type Tag
|
||||
} from '@hcengineering/card'
|
||||
@@ -33,8 +34,10 @@ import chunter from '@hcengineering/chunter'
|
||||
import core, {
|
||||
AccountRole,
|
||||
type Blobs,
|
||||
type Class,
|
||||
ClassifierKind,
|
||||
type CollectionSize,
|
||||
type Doc,
|
||||
DOMAIN_MODEL,
|
||||
DOMAIN_SPACE,
|
||||
IndexKind,
|
||||
@@ -45,6 +48,7 @@ import core, {
|
||||
SortingOrder
|
||||
} from '@hcengineering/core'
|
||||
import {
|
||||
ArrOf,
|
||||
type Builder,
|
||||
Collection,
|
||||
Hidden,
|
||||
@@ -52,15 +56,15 @@ import {
|
||||
Mixin,
|
||||
Model,
|
||||
Prop,
|
||||
ReadOnly,
|
||||
TypeCollaborativeDoc,
|
||||
TypeNumber,
|
||||
TypeRef,
|
||||
TypeString,
|
||||
UX,
|
||||
ReadOnly
|
||||
UX
|
||||
} from '@hcengineering/model'
|
||||
import attachment from '@hcengineering/model-attachment'
|
||||
import { TAttachedDoc, TClass, TDoc, TMixin, TSpace } from '@hcengineering/model-core'
|
||||
import { TRole as TBaseRole, TClass, TDoc, TMixin, TTypedSpace } from '@hcengineering/model-core'
|
||||
import { createPublicLinkAction } from '@hcengineering/model-guest'
|
||||
import preference, { TPreference } from '@hcengineering/model-preference'
|
||||
import presentation from '@hcengineering/model-presentation'
|
||||
@@ -72,8 +76,9 @@ import time, { type ToDo } from '@hcengineering/time'
|
||||
import { PaletteColorIndexes } from '@hcengineering/ui/src/colors'
|
||||
import { type AnyComponent } from '@hcengineering/ui/src/types'
|
||||
import { type BuildModelKey } from '@hcengineering/view'
|
||||
import card from './plugin'
|
||||
import { createActions } from './actions'
|
||||
import card from './plugin'
|
||||
import { definePermissions } from './permissions'
|
||||
|
||||
export { cardId } from '@hcengineering/card'
|
||||
|
||||
@@ -141,10 +146,11 @@ export class TCard extends TDoc implements Card {
|
||||
peerId?: string
|
||||
}
|
||||
|
||||
@Model(card.class.CardSpace, core.class.Space, DOMAIN_SPACE)
|
||||
@Model(card.class.CardSpace, core.class.TypedSpace, DOMAIN_SPACE)
|
||||
@UX(core.string.Space)
|
||||
export class TCardSpace extends TSpace implements CardSpace {
|
||||
types!: Ref<MasterTag>[]
|
||||
export class TCardSpace extends TTypedSpace implements CardSpace {
|
||||
@Prop(ArrOf(TypeRef(card.class.MasterTag)), card.string.MasterTags)
|
||||
types!: Ref<MasterTag>[]
|
||||
}
|
||||
|
||||
@Model(card.class.MasterTagEditorSection, core.class.Doc, DOMAIN_MODEL)
|
||||
@@ -169,11 +175,9 @@ export class TCardViewDefaults extends TMasterTag implements CardViewDefaults {
|
||||
defaultNavigation?: string
|
||||
}
|
||||
|
||||
@Model(card.class.Role, core.class.AttachedDoc, DOMAIN_MODEL)
|
||||
export class TRole extends TAttachedDoc implements Role {
|
||||
name!: string
|
||||
declare attachedTo: Ref<MasterTag | Tag>
|
||||
declare collection: 'roles'
|
||||
@Model(card.class.Role, core.class.Role, DOMAIN_MODEL)
|
||||
export class TRole extends TBaseRole implements Role {
|
||||
type!: Ref<MasterTag | Tag>
|
||||
}
|
||||
|
||||
@Model(card.class.FavoriteCard, preference.class.Preference)
|
||||
@@ -187,6 +191,11 @@ export class TFavoriteType extends TPreference implements FavoriteType {
|
||||
declare attachedTo: Ref<MasterTag>
|
||||
}
|
||||
|
||||
@Model(card.class.PermissionObjectClass, core.class.Doc, DOMAIN_MODEL)
|
||||
export class TPermissionObjectClass extends TDoc implements PermissionObjectClass {
|
||||
objectClass!: Ref<Class<Doc>>
|
||||
}
|
||||
|
||||
@Mixin(card.mixin.CreateCardExtension, card.class.MasterTag)
|
||||
export class TCreateCardExtension extends TMasterTag implements CreateCardExtension {
|
||||
component?: AnyComponent
|
||||
@@ -355,6 +364,7 @@ export function createSystemType (
|
||||
|
||||
export function createModel (builder: Builder): void {
|
||||
builder.createModel(
|
||||
TPermissionObjectClass,
|
||||
TMasterTag,
|
||||
TTag,
|
||||
TCard,
|
||||
@@ -368,7 +378,20 @@ export function createModel (builder: Builder): void {
|
||||
TCreateCardExtension
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
core.class.SpaceType,
|
||||
core.space.Model,
|
||||
{
|
||||
name: '',
|
||||
descriptor: core.descriptor.SpacesType,
|
||||
roles: 0,
|
||||
targetClass: core.mixin.SpacesTypeData
|
||||
},
|
||||
card.spaceType.SpaceType
|
||||
)
|
||||
|
||||
defineTabs(builder)
|
||||
definePermissions(builder)
|
||||
|
||||
builder.mixin(card.class.Card, core.class.Class, view.mixin.ObjectIcon, {
|
||||
component: card.component.CardIcon
|
||||
|
||||
@@ -13,8 +13,16 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { type Card, cardId, DOMAIN_CARD } from '@hcengineering/card'
|
||||
import core, { DOMAIN_MODEL, type Ref, TxOperations, type Client, type Data, type Doc } from '@hcengineering/core'
|
||||
import cardPlugin, { type Card, cardId, DOMAIN_CARD, type Role } from '@hcengineering/card'
|
||||
import core, {
|
||||
DOMAIN_MODEL,
|
||||
type Ref,
|
||||
TxOperations,
|
||||
type Client,
|
||||
type Data,
|
||||
type Doc,
|
||||
type DocumentUpdate
|
||||
} from '@hcengineering/core'
|
||||
import {
|
||||
tryMigrate,
|
||||
tryUpgrade,
|
||||
@@ -82,11 +90,42 @@ export const cardOperation: MigrateOperation = {
|
||||
state: 'make-config-sortable',
|
||||
mode: 'upgrade',
|
||||
func: makeConfigSortable
|
||||
},
|
||||
{
|
||||
state: 'migrate-roles-v2',
|
||||
mode: 'upgrade',
|
||||
func: migrateRolesToBaseRole
|
||||
},
|
||||
{
|
||||
state: 'add-space-type',
|
||||
mode: 'upgrade',
|
||||
func: addSpaceType
|
||||
}
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
async function addSpaceType (client: MigrationUpgradeClient): Promise<void> {
|
||||
const txOp = new TxOperations(client, core.account.System)
|
||||
const spaces = await client.findAll(card.class.CardSpace, { type: { $exists: false } })
|
||||
for (const space of spaces) {
|
||||
await txOp.diffUpdate(space, { type: cardPlugin.spaceType.SpaceType })
|
||||
}
|
||||
}
|
||||
|
||||
async function migrateRolesToBaseRole (client: MigrationUpgradeClient): Promise<void> {
|
||||
const txOp = new TxOperations(client, core.account.System)
|
||||
const roles = await client.findAll(card.class.Role, { attachedTo: { $ne: cardPlugin.spaceType.SpaceType } })
|
||||
for (const role of roles) {
|
||||
const baseRoleData: DocumentUpdate<Role> = {
|
||||
type: role.attachedTo as any,
|
||||
attachedTo: cardPlugin.spaceType.SpaceType,
|
||||
attachedToClass: core.class.SpaceType
|
||||
}
|
||||
await txOp.update(role, baseRoleData)
|
||||
}
|
||||
}
|
||||
|
||||
async function fillParentInfo (client: Client): Promise<void> {
|
||||
const txOp = new TxOperations(client, core.account.System)
|
||||
const cards = await client.findAll(card.class.Card, { parentInfo: { $exists: false }, parent: { $ne: null } })
|
||||
@@ -249,6 +288,7 @@ async function createDefaultProject (tx: TxOperations): Promise<void> {
|
||||
members: [],
|
||||
archived: false,
|
||||
autoJoin: true,
|
||||
type: card.spaceType.SpaceType,
|
||||
types: topLevelTypes.map((it) => it._id)
|
||||
},
|
||||
card.space.Default
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
// 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.
|
||||
|
||||
import core from '@hcengineering/core'
|
||||
import { type Builder } from '@hcengineering/model'
|
||||
import card from '.'
|
||||
|
||||
export function definePermissions (builder: Builder): void {
|
||||
builder.createDoc(
|
||||
core.class.Permission,
|
||||
core.space.Model,
|
||||
{
|
||||
label: card.string.AddTagPermission,
|
||||
txClass: core.class.TxMixin,
|
||||
objectClass: card.class.Card,
|
||||
scope: 'space'
|
||||
},
|
||||
card.permission.AddTag
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
core.class.Permission,
|
||||
core.space.Model,
|
||||
{
|
||||
label: card.string.RemoveTag,
|
||||
txClass: core.class.TxUpdateDoc,
|
||||
txMatch: {
|
||||
'operations.$unset': {
|
||||
$exists: true
|
||||
}
|
||||
},
|
||||
objectClass: card.class.Card,
|
||||
scope: 'space'
|
||||
},
|
||||
card.permission.RemoveTag
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
core.class.Permission,
|
||||
core.space.Model,
|
||||
{
|
||||
label: card.string.CreateCardPermission,
|
||||
txClass: core.class.TxCreateDoc,
|
||||
objectClass: card.class.Card,
|
||||
scope: 'space'
|
||||
},
|
||||
card.permission.CreateCard
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
core.class.Permission,
|
||||
core.space.Model,
|
||||
{
|
||||
label: card.string.UpdateCard,
|
||||
txClass: core.class.TxUpdateDoc,
|
||||
objectClass: card.class.Card,
|
||||
scope: 'space'
|
||||
},
|
||||
card.permission.UpdateCard
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
core.class.Permission,
|
||||
core.space.Model,
|
||||
{
|
||||
label: card.string.RemoveCard,
|
||||
txClass: core.class.TxRemoveDoc,
|
||||
objectClass: card.class.Card,
|
||||
scope: 'space'
|
||||
},
|
||||
card.permission.RemoveCard
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
core.class.Permission,
|
||||
core.space.Model,
|
||||
{
|
||||
label: card.string.ForbidAddTagPermission,
|
||||
txClass: core.class.TxMixin,
|
||||
objectClass: card.class.Card,
|
||||
scope: 'space',
|
||||
forbid: true
|
||||
},
|
||||
card.permission.ForbidAddTag
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
core.class.Permission,
|
||||
core.space.Model,
|
||||
{
|
||||
label: card.string.ForbidRemoveTag,
|
||||
txClass: core.class.TxUpdateDoc,
|
||||
txMatch: {
|
||||
'operations.$unset': {
|
||||
$exists: true
|
||||
}
|
||||
},
|
||||
objectClass: card.class.Card,
|
||||
scope: 'space',
|
||||
forbid: true
|
||||
},
|
||||
card.permission.ForbidRemoveTag
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
core.class.Permission,
|
||||
core.space.Model,
|
||||
{
|
||||
label: card.string.ForbidCreateCardPermission,
|
||||
txClass: core.class.TxCreateDoc,
|
||||
objectClass: card.class.Card,
|
||||
scope: 'space',
|
||||
forbid: true
|
||||
},
|
||||
card.permission.ForbidCreateCard
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
core.class.Permission,
|
||||
core.space.Model,
|
||||
{
|
||||
label: card.string.ForbidUpdateCard,
|
||||
txClass: core.class.TxUpdateDoc,
|
||||
objectClass: card.class.Card,
|
||||
scope: 'space',
|
||||
forbid: true
|
||||
},
|
||||
card.permission.ForbidUpdateCard
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
core.class.Permission,
|
||||
core.space.Model,
|
||||
{
|
||||
label: card.string.ForbidRemoveCard,
|
||||
txClass: core.class.TxRemoveDoc,
|
||||
objectClass: card.class.Card,
|
||||
scope: 'space',
|
||||
forbid: true
|
||||
},
|
||||
card.permission.ForbidRemoveCard
|
||||
)
|
||||
}
|
||||
@@ -17,11 +17,11 @@ 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 { mergeIds, type Resource } from '@hcengineering/platform'
|
||||
import { type Location, type ResolvedLocation } from '@hcengineering/ui/src/types'
|
||||
import { type LocationData } from '@hcengineering/workbench'
|
||||
import { type ActionCategory, type Action, type ViewAction } from '@hcengineering/view'
|
||||
import { type IntlString, 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'
|
||||
import { type LocationData } from '@hcengineering/workbench'
|
||||
|
||||
export default mergeIds(cardId, card, {
|
||||
app: {
|
||||
@@ -37,6 +37,28 @@ export default mergeIds(cardId, card, {
|
||||
UnsetParent: '' as Ref<Action<Doc, any>>,
|
||||
PublicLink: '' as Ref<Action<Doc, any>>
|
||||
},
|
||||
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>
|
||||
|
||||
@@ -74,6 +74,7 @@ import { defineMethods } from './actions'
|
||||
import { defineTriggers } from './triggers'
|
||||
import { defineFunctions } from './functions'
|
||||
import process from './plugin'
|
||||
import { definePermissions } from './permission'
|
||||
|
||||
const DOMAIN_PROCESS = 'process' as Domain
|
||||
const DOMAIN_PROCESS_LOG = 'process-log' as Domain
|
||||
@@ -673,6 +674,12 @@ export function createModel (builder: Builder): void {
|
||||
modes: ['Equal', 'NotEqual', 'Exists']
|
||||
}
|
||||
})
|
||||
|
||||
definePermissions(builder)
|
||||
|
||||
builder.createDoc(card.class.PermissionObjectClass, core.space.Model, {
|
||||
objectClass: process.class.Execution
|
||||
})
|
||||
}
|
||||
|
||||
export { processId } from '@hcengineering/process'
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
import core from '@hcengineering/core'
|
||||
import process from '.'
|
||||
import { type Builder } from '@hcengineering/model'
|
||||
import { ExecutionStatus } from '@hcengineering/process'
|
||||
|
||||
export function definePermissions (builder: Builder): void {
|
||||
builder.createDoc(
|
||||
core.class.Permission,
|
||||
core.space.Model,
|
||||
{
|
||||
label: process.string.RunProcessPermission,
|
||||
txClass: core.class.TxCreateDoc,
|
||||
objectClass: process.class.Execution,
|
||||
scope: 'space'
|
||||
},
|
||||
process.permission.RunProcess
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
core.class.Permission,
|
||||
core.space.Model,
|
||||
{
|
||||
label: process.string.CancelProcessPermission,
|
||||
txClass: core.class.TxUpdateDoc,
|
||||
objectClass: process.class.Execution,
|
||||
txMatch: {
|
||||
'operations.status': ExecutionStatus.Cancelled
|
||||
},
|
||||
scope: 'space'
|
||||
},
|
||||
process.permission.CancelProcess
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
core.class.Permission,
|
||||
core.space.Model,
|
||||
{
|
||||
label: process.string.ForbidRunProcessPermission,
|
||||
txClass: core.class.TxCreateDoc,
|
||||
objectClass: process.class.Execution,
|
||||
scope: 'space',
|
||||
forbid: true
|
||||
},
|
||||
process.permission.ForbidRunProcess
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
core.class.Permission,
|
||||
core.space.Model,
|
||||
{
|
||||
label: process.string.ForbidCancelProcessPermission,
|
||||
txClass: core.class.TxUpdateDoc,
|
||||
objectClass: process.class.Execution,
|
||||
txMatch: {
|
||||
'operations.status': ExecutionStatus.Cancelled
|
||||
},
|
||||
scope: 'space',
|
||||
forbid: true
|
||||
},
|
||||
process.permission.ForbidCancelProcess
|
||||
)
|
||||
}
|
||||
@@ -11,13 +11,13 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { type Doc, type Ref } from '@hcengineering/core'
|
||||
import { type IntlString, mergeIds } from '@hcengineering/platform'
|
||||
import { processId } from '@hcengineering/process'
|
||||
import { type PresentationMiddlewareFactory } from '@hcengineering/presentation/src/pipeline'
|
||||
import process from '@hcengineering/process-resources/src/plugin'
|
||||
import { type ViewAction, type Action } from '@hcengineering/view'
|
||||
import { type CardSection } from '@hcengineering/card'
|
||||
import { type Doc, type Ref } from '@hcengineering/core'
|
||||
import { mergeIds, type IntlString } from '@hcengineering/platform'
|
||||
import { type PresentationMiddlewareFactory } from '@hcengineering/presentation/src/pipeline'
|
||||
import { processId } from '@hcengineering/process'
|
||||
import process from '@hcengineering/process-resources/src/plugin'
|
||||
import { type Action, type ViewAction } from '@hcengineering/view'
|
||||
|
||||
export default mergeIds(processId, process, {
|
||||
app: {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import type { Class, Doc, Ref } from '@hcengineering/core'
|
||||
import { checkForbiddenPermission, type Class, type Doc, type Ref } from '@hcengineering/core'
|
||||
import type { AnySvelteComponent, ButtonKind, ButtonSize } from '@hcengineering/ui'
|
||||
import { Icon, Label, tooltip } from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
@@ -67,7 +67,7 @@
|
||||
|
||||
$: attribute = typeof key === 'string' ? hierarchy.getAttribute(_class, key) : key.attr
|
||||
$: attributeKey = typeof key === 'string' ? key : key.key
|
||||
$: isReadonly = (attribute.readonly ?? false) || readonly
|
||||
$: isReadonly = readonly || (attribute.readonly ?? false)
|
||||
|
||||
$: icon = attribute?.icon ?? attribute?.type?.icon
|
||||
</script>
|
||||
|
||||
@@ -49,6 +49,16 @@
|
||||
"CardContent": "Co chcete sdílet?",
|
||||
"Feed": "Kanál",
|
||||
"AllCards": "Všechny karty",
|
||||
"Favorites": "Oblíbené"
|
||||
"Favorites": "Oblíbené",
|
||||
"RemoveCard": "Odstranit kartu",
|
||||
"UpdateCard": "Aktualizovat kartu",
|
||||
"CreateCardPermission": "Vytvořit kartu",
|
||||
"AddTagPermission": "Přidat štítek",
|
||||
"RemoveTag": "Odstranit štítek",
|
||||
"ForbidRemoveCard": "Zakázat odstranění karty",
|
||||
"ForbidUpdateCard": "Zakázat aktualizaci karty",
|
||||
"ForbidCreateCardPermission": "Zakázat vytváření karet",
|
||||
"ForbidAddTagPermission": "Zakázat přidávání štítků",
|
||||
"ForbidRemoveTag": "Zakázat odebírání štítků"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,16 @@
|
||||
"CardContent": "Was möchten Sie teilen?",
|
||||
"Feed": "Feed",
|
||||
"AllCards": "Alle Karten",
|
||||
"Favorites": "Favoriten"
|
||||
"Favorites": "Favoriten",
|
||||
"RemoveCard": "Karte entfernen",
|
||||
"UpdateCard": "Karte aktualisieren",
|
||||
"CreateCardPermission": "Karte erstellen",
|
||||
"AddTagPermission": "Tag hinzufügen",
|
||||
"RemoveTag": "Tag entfernen",
|
||||
"ForbidRemoveCard": "Entfernen der Karte verbieten",
|
||||
"ForbidUpdateCard": "Aktualisieren der Karte verbieten",
|
||||
"ForbidCreateCardPermission": "Erstellen von Karten verbieten",
|
||||
"ForbidAddTagPermission": "Hinzufügen von Tags verbieten",
|
||||
"ForbidRemoveTag": "Entfernen von Tags verbieten"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,16 @@
|
||||
"CardContent": "What do you want to share?",
|
||||
"Feed": "Feed",
|
||||
"AllCards": "All Cards",
|
||||
"Favorites": "Favorites"
|
||||
"Favorites": "Favorites",
|
||||
"RemoveCard": "Remove Card",
|
||||
"UpdateCard": "Update Card",
|
||||
"CreateCardPermission": "Create Card",
|
||||
"AddTagPermission": "Add Tag",
|
||||
"RemoveTag": "Remove Tag",
|
||||
"ForbidRemoveCard": "Forbid Remove Card",
|
||||
"ForbidUpdateCard": "Forbid Update Card",
|
||||
"ForbidCreateCardPermission": "Forbid Create Card",
|
||||
"ForbidAddTagPermission": "Forbid Add Tag",
|
||||
"ForbidRemoveTag": "Forbid Remove Tag"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,16 @@
|
||||
"CardContent": "¿Qué quieres compartir?",
|
||||
"Feed": "Feed",
|
||||
"AllCards": "Todas las Tarjetas",
|
||||
"Favorites": "Favoritos"
|
||||
"Favorites": "Favoritos",
|
||||
"RemoveCard": "Eliminar tarjeta",
|
||||
"UpdateCard": "Actualizar tarjeta",
|
||||
"CreateCardPermission": "Crear tarjeta",
|
||||
"AddTagPermission": "Añadir etiqueta",
|
||||
"RemoveTag": "Eliminar etiqueta",
|
||||
"ForbidRemoveCard": "Prohibir eliminar tarjeta",
|
||||
"ForbidUpdateCard": "Prohibir actualizar tarjeta",
|
||||
"ForbidCreateCardPermission": "Prohibir crear tarjeta",
|
||||
"ForbidAddTagPermission": "Prohibir añadir etiqueta",
|
||||
"ForbidRemoveTag": "Prohibir eliminar etiqueta"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,16 @@
|
||||
"CardContent": "Que voulez-vous partager ?",
|
||||
"Feed": "Flux",
|
||||
"AllCards": "Toutes les Cartes",
|
||||
"Favorites": "Favoris"
|
||||
"Favorites": "Favoris",
|
||||
"RemoveCard": "Supprimer la fiche",
|
||||
"UpdateCard": "Mettre à jour la fiche",
|
||||
"CreateCardPermission": "Créer une fiche",
|
||||
"AddTagPermission": "Ajouter une étiquette",
|
||||
"RemoveTag": "Supprimer l'étiquette",
|
||||
"ForbidRemoveCard": "Interdire la suppression de la fiche",
|
||||
"ForbidUpdateCard": "Interdire la mise à jour de la fiche",
|
||||
"ForbidCreateCardPermission": "Interdire la création de fiche",
|
||||
"ForbidAddTagPermission": "Interdire l'ajout d'étiquette",
|
||||
"ForbidRemoveTag": "Interdire la suppression d'étiquette"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,16 @@
|
||||
"CardContent": "Cosa vuoi condividere?",
|
||||
"Feed": "Feed",
|
||||
"AllCards": "Tutte le Carte",
|
||||
"Favorites": "Preferiti"
|
||||
"Favorites": "Preferiti",
|
||||
"RemoveCard": "Rimuovi scheda",
|
||||
"UpdateCard": "Aggiorna scheda",
|
||||
"CreateCardPermission": "Crea scheda",
|
||||
"AddTagPermission": "Aggiungi tag",
|
||||
"RemoveTag": "Rimuovi tag",
|
||||
"ForbidRemoveCard": "Vieta rimozione scheda",
|
||||
"ForbidUpdateCard": "Vieta aggiornamento scheda",
|
||||
"ForbidCreateCardPermission": "Vieta creazione scheda",
|
||||
"ForbidAddTagPermission": "Vieta aggiunta tag",
|
||||
"ForbidRemoveTag": "Vieta rimozione tag"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,16 @@
|
||||
"CardContent": "何を共有しますか?",
|
||||
"Feed": "フィード",
|
||||
"AllCards": "すべてのカード",
|
||||
"Favorites": "お気に入り"
|
||||
"Favorites": "お気に入り",
|
||||
"RemoveCard": "カードを削除",
|
||||
"UpdateCard": "カードを更新",
|
||||
"CreateCardPermission": "カードを作成",
|
||||
"AddTagPermission": "タグを追加",
|
||||
"RemoveTag": "タグを削除",
|
||||
"ForbidRemoveCard": "カード削除を禁止",
|
||||
"ForbidUpdateCard": "カード更新を禁止",
|
||||
"ForbidCreateCardPermission": "カード作成を禁止",
|
||||
"ForbidAddTagPermission": "タグ追加を禁止",
|
||||
"ForbidRemoveTag": "タグ削除を禁止"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,16 @@
|
||||
"CardContent": "O que você quer compartilhar?",
|
||||
"Feed": "Feed",
|
||||
"AllCards": "Todos os Cartões",
|
||||
"Favorites": "Favoritos"
|
||||
"Favorites": "Favoritos",
|
||||
"RemoveCard": "Remover cartão",
|
||||
"UpdateCard": "Atualizar cartão",
|
||||
"CreateCardPermission": "Criar cartão",
|
||||
"AddTagPermission": "Adicionar etiqueta",
|
||||
"RemoveTag": "Remover etiqueta",
|
||||
"ForbidRemoveCard": "Proibir remoção de cartão",
|
||||
"ForbidUpdateCard": "Proibir atualização de cartão",
|
||||
"ForbidCreateCardPermission": "Proibir criação de cartão",
|
||||
"ForbidAddTagPermission": "Proibir adicionar etiqueta",
|
||||
"ForbidRemoveTag": "Proibir remover etiqueta"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,16 @@
|
||||
"CardContent": "Чем вы хотите поделиться?",
|
||||
"Feed": "Лента",
|
||||
"AllCards": "Все карты",
|
||||
"Favorites": "Избранное"
|
||||
"Favorites": "Избранное",
|
||||
"RemoveCard": "Удалить карточку",
|
||||
"UpdateCard": "Обновить карточку",
|
||||
"CreateCardPermission": "Создать карточку",
|
||||
"AddTagPermission": "Добавить тег",
|
||||
"RemoveTag": "Удалить тег",
|
||||
"ForbidRemoveCard": "Запретить удаление карточки",
|
||||
"ForbidUpdateCard": "Запретить обновление карточки",
|
||||
"ForbidCreateCardPermission": "Запретить создание карточки",
|
||||
"ForbidAddTagPermission": "Запретить добавление тега",
|
||||
"ForbidRemoveTag": "Запретить удаление тега"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,16 @@
|
||||
"CardContent": "Ne paylaşmak istiyorsunuz?",
|
||||
"Feed": "Akış",
|
||||
"AllCards": "Tüm Kartlar",
|
||||
"Favorites": "Favoriler"
|
||||
"Favorites": "Favoriler",
|
||||
"RemoveCard": "Kartı kaldır",
|
||||
"UpdateCard": "Kartı güncelle",
|
||||
"CreateCardPermission": "Kart oluştur",
|
||||
"AddTagPermission": "Etiket ekle",
|
||||
"RemoveTag": "Etiketi kaldır",
|
||||
"ForbidRemoveCard": "Kart kaldırmayı yasakla",
|
||||
"ForbidUpdateCard": "Kart güncellemeyi yasakla",
|
||||
"ForbidCreateCardPermission": "Kart oluşturmayı yasakla",
|
||||
"ForbidAddTagPermission": "Etiket eklemeyi yasakla",
|
||||
"ForbidRemoveTag": "Etiket kaldırmayı yasakla"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,16 @@
|
||||
"CardContent": "你想分享什么?",
|
||||
"Feed": "动态",
|
||||
"AllCards": "所有卡片",
|
||||
"Favorites": "收藏夹"
|
||||
"Favorites": "收藏夹",
|
||||
"RemoveCard": "删除卡片",
|
||||
"UpdateCard": "更新卡片",
|
||||
"CreateCardPermission": "创建卡片",
|
||||
"AddTagPermission": "添加标签",
|
||||
"RemoveTag": "移除标签",
|
||||
"ForbidRemoveCard": "禁止删除卡片",
|
||||
"ForbidUpdateCard": "禁止更新卡片",
|
||||
"ForbidCreateCardPermission": "禁止创建卡片",
|
||||
"ForbidAddTagPermission": "禁止添加标签",
|
||||
"ForbidRemoveTag": "禁止移除标签"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,17 +13,20 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import core, { Class, Doc, Ref, toRank } from '@hcengineering/core'
|
||||
import { Card } from '@hcengineering/card'
|
||||
import { PermissionsStore } from '@hcengineering/contact'
|
||||
import { checkMyPermission, permissionsStore } from '@hcengineering/contact-resources'
|
||||
import core, { AnyAttribute, Class, Doc, Permission, Ref, toRank, TypedSpace } from '@hcengineering/core'
|
||||
import {
|
||||
AttributeBarEditor,
|
||||
KeyedAttribute,
|
||||
createQuery,
|
||||
getClient,
|
||||
getFiltredKeys,
|
||||
isCollectionAttr
|
||||
isCollectionAttr,
|
||||
KeyedAttribute
|
||||
} from '@hcengineering/presentation'
|
||||
|
||||
export let object: Doc | Record<string, any>
|
||||
export let object: Card
|
||||
export let _class: Ref<Class<Doc>>
|
||||
export let to: Ref<Class<Doc>> | undefined = core.class.Doc
|
||||
export let ignoreKeys: string[] = []
|
||||
@@ -53,11 +56,24 @@
|
||||
$: query.query(core.class.Attribute, { attributeOf: _class }, () => {
|
||||
updateKeys(_class, ignoreKeys, to)
|
||||
})
|
||||
|
||||
function checkForbiddenPermission (attr: AnyAttribute, permissionsStore: PermissionsStore): boolean {
|
||||
const _id = `${attr._id}_forbidden` as Ref<Permission>
|
||||
return checkMyPermission(_id, object.space as Ref<TypedSpace>, permissionsStore)
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="grid" class:fourRows>
|
||||
{#each keys as key (typeof key === 'string' ? key : key.key)}
|
||||
<AttributeBarEditor {key} {_class} {object} {showHeader} {readonly} withIcon on:update />
|
||||
{#each keys as key}
|
||||
<AttributeBarEditor
|
||||
{key}
|
||||
{_class}
|
||||
{object}
|
||||
{showHeader}
|
||||
readonly={readonly || checkForbiddenPermission(key.attr, $permissionsStore)}
|
||||
withIcon
|
||||
on:update
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
import { TypeSelector } from '../index'
|
||||
|
||||
export let title: string = ''
|
||||
export let type: Ref<MasterTag> = 'chat:masterTag:Thread' as Ref<MasterTag>
|
||||
export let type: Ref<MasterTag> = card.types.Document
|
||||
export let space: CardSpace | undefined = undefined
|
||||
export let changeType: boolean = false
|
||||
export let allowChangeSpace: boolean = true
|
||||
|
||||
@@ -15,13 +15,16 @@
|
||||
//
|
||||
-->
|
||||
<script lang="ts">
|
||||
import card, { Card, Tag } from '@hcengineering/card'
|
||||
import { Class, Doc, Mixin, Ref } from '@hcengineering/core'
|
||||
import { Card, Tag } from '@hcengineering/card'
|
||||
import { Class, Doc, Mixin, Permission, Ref, TypedSpace } from '@hcengineering/core'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { CircleButton, eventToHTMLElement, IconAdd, IconDownOutline, SelectPopup, showPopup } from '@hcengineering/ui'
|
||||
|
||||
import MasterTagSelector from './MasterTagSelector.svelte'
|
||||
import CardTagColored from './CardTagColored.svelte'
|
||||
import { PermissionsStore } from '@hcengineering/contact'
|
||||
import { checkMyPermission, permissionsStore } from '@hcengineering/contact-resources'
|
||||
import card from '../plugin'
|
||||
|
||||
export let doc: Card
|
||||
export let dropdownTags: boolean = false
|
||||
@@ -81,6 +84,18 @@
|
||||
return !desc.some((p) => hierarchy.hasMixin(doc, p) && p !== mixinId)
|
||||
}
|
||||
|
||||
function checkForbiddenPermission (permission: Ref<Permission>, permissionsStore: PermissionsStore): boolean {
|
||||
return checkMyPermission(permission, doc.space as Ref<TypedSpace>, permissionsStore)
|
||||
}
|
||||
|
||||
function checkRemovePermission (permissionsStore: PermissionsStore): boolean {
|
||||
return checkForbiddenPermission(card.permission.ForbidRemoveTag, permissionsStore)
|
||||
}
|
||||
|
||||
function checkAddPermission (permissionsStore: PermissionsStore): boolean {
|
||||
return checkForbiddenPermission(card.permission.ForbidAddTag, permissionsStore)
|
||||
}
|
||||
|
||||
const handleDrop = (e: MouseEvent): void => {
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
@@ -116,7 +131,7 @@
|
||||
/>
|
||||
{:else}
|
||||
{#each activeTags as mixin}
|
||||
{@const removable = isRemoveable(mixin._id, activeTags)}
|
||||
{@const removable = isRemoveable(mixin._id, activeTags) && !checkRemovePermission($permissionsStore)}
|
||||
<CardTagColored
|
||||
labelIntl={mixin.label}
|
||||
color={mixin.background ?? 0}
|
||||
@@ -124,7 +139,7 @@
|
||||
on:remove={() => removeTag(mixin._id)}
|
||||
/>
|
||||
{/each}
|
||||
{#if dropdownItems.length > 0}
|
||||
{#if dropdownItems.length > 0 && !checkAddPermission($permissionsStore)}
|
||||
<CircleButton id={id ? `${id}-add` : undefined} icon={IconAdd} size={'small'} ghost on:click={add} />
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
@@ -13,15 +13,17 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { AccountArrayEditor } from '@hcengineering/contact-resources'
|
||||
import core, { AccountUuid, Data, Ref, getCurrentAccount } from '@hcengineering/core'
|
||||
import { AccountArrayEditor, employeeRefByAccountUuidStore } from '@hcengineering/contact-resources'
|
||||
import core, { AccountUuid, Data, Ref, RolesAssignment, getCurrentAccount, notEmpty } from '@hcengineering/core'
|
||||
import presentation, { Card, getClient } from '@hcengineering/presentation'
|
||||
import { EditBox, Label, Toggle } from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
|
||||
import { CardSpace, MasterTag } from '@hcengineering/card'
|
||||
import { CardSpace, MasterTag, Role } from '@hcengineering/card'
|
||||
import card from '../../plugin'
|
||||
import TypesSelector from './TypesSelector.svelte'
|
||||
import view from '@hcengineering/view'
|
||||
import { deepEqual } from 'fast-equals'
|
||||
|
||||
export let space: CardSpace | undefined = undefined
|
||||
|
||||
@@ -29,12 +31,18 @@
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
|
||||
let name: string = space?.name ?? ''
|
||||
const topLevelTypes = client.getModel().findAllSync(card.class.MasterTag, {
|
||||
extends: card.class.Card
|
||||
})
|
||||
|
||||
let types: Ref<MasterTag>[] =
|
||||
space?.types !== undefined ? hierarchy.clone(space.types) : topLevelTypes.map((it) => it._id)
|
||||
|
||||
let roles = client.getModel().findAllSync(card.class.Role, { type: { $in: types } })
|
||||
$: roles = client.getModel().findAllSync(card.class.Role, { type: { $in: types } })
|
||||
|
||||
let name: string = space?.name ?? ''
|
||||
|
||||
let isPrivate: boolean = space?.private ?? false
|
||||
let members: AccountUuid[] =
|
||||
space?.members !== undefined ? hierarchy.clone(space.members) : [getCurrentAccount().uuid]
|
||||
@@ -42,6 +50,23 @@
|
||||
|
||||
$: isNew = space === undefined
|
||||
|
||||
let rolesAssignment = getRolesAssignment(roles)
|
||||
$: rolesAssignment = getRolesAssignment(roles)
|
||||
|
||||
function getRolesAssignment (roles: Role[]): RolesAssignment {
|
||||
if (space === undefined || roles === undefined) {
|
||||
return {}
|
||||
}
|
||||
|
||||
const asMixin = hierarchy.as(space, core.mixin.SpacesTypeData)
|
||||
|
||||
return roles.reduce<RolesAssignment>((prev, { _id }) => {
|
||||
prev[_id] = (asMixin as any)[_id] ?? []
|
||||
|
||||
return prev
|
||||
}, {})
|
||||
}
|
||||
|
||||
async function handleSave (): Promise<void> {
|
||||
if (isNew) {
|
||||
await create()
|
||||
@@ -59,6 +84,7 @@
|
||||
owners,
|
||||
autoJoin,
|
||||
archived: false,
|
||||
type: card.spaceType.SpaceType,
|
||||
types
|
||||
}
|
||||
}
|
||||
@@ -71,6 +97,10 @@
|
||||
const data = getData()
|
||||
await client.diffUpdate(space, data)
|
||||
|
||||
if (rolesAssignment && !deepEqual(rolesAssignment, getRolesAssignment(roles))) {
|
||||
await client.updateMixin(space._id, space._class, core.space.Space, core.mixin.SpacesTypeData, rolesAssignment)
|
||||
}
|
||||
|
||||
close()
|
||||
}
|
||||
|
||||
@@ -79,6 +109,10 @@
|
||||
|
||||
const id = await client.createDoc(card.class.CardSpace, core.space.Space, { ...teamspaceData })
|
||||
|
||||
if (rolesAssignment && !deepEqual(rolesAssignment, getRolesAssignment(roles))) {
|
||||
await client.updateMixin(id, card.class.CardSpace, core.space.Space, core.mixin.SpacesTypeData, rolesAssignment)
|
||||
}
|
||||
|
||||
close(id)
|
||||
}
|
||||
|
||||
@@ -104,6 +138,16 @@
|
||||
!(members.length === 0 && isPrivate) &&
|
||||
owners.length > 0 &&
|
||||
(!isPrivate || owners.some((o) => members.includes(o)))
|
||||
|
||||
$: membersPersons = members.map((m) => $employeeRefByAccountUuidStore.get(m)).filter(notEmpty)
|
||||
|
||||
function handleRoleAssignmentChanged (roleId: Ref<Role>, newMembers: AccountUuid[]): void {
|
||||
if (rolesAssignment === undefined) {
|
||||
rolesAssignment = {}
|
||||
}
|
||||
|
||||
rolesAssignment[roleId] = newMembers
|
||||
}
|
||||
</script>
|
||||
|
||||
<Card
|
||||
@@ -178,5 +222,24 @@
|
||||
</div>
|
||||
<Toggle id={'teamspace-autoJoin'} bind:on={autoJoin} />
|
||||
</div>
|
||||
|
||||
{#each roles as role}
|
||||
<div class="antiGrid-row">
|
||||
<div class="antiGrid-row__header">
|
||||
<Label label={view.string.RoleLabel} params={{ role: role.name }} />
|
||||
</div>
|
||||
<AccountArrayEditor
|
||||
value={rolesAssignment?.[role._id] ?? []}
|
||||
label={core.string.Members}
|
||||
includeItems={membersPersons}
|
||||
readonly={membersPersons.length === 0}
|
||||
onChange={(refs) => {
|
||||
handleRoleAssignmentChanged(role._id, refs)
|
||||
}}
|
||||
kind={'regular'}
|
||||
size={'large'}
|
||||
/>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
@@ -31,11 +31,13 @@
|
||||
const _id = await client.addCollection(
|
||||
card.class.Role,
|
||||
core.space.Model,
|
||||
masterTag._id,
|
||||
masterTag._class,
|
||||
card.spaceType.SpaceType,
|
||||
core.class.SpaceType,
|
||||
'roles',
|
||||
{
|
||||
name: value
|
||||
name: value,
|
||||
type: masterTag._id,
|
||||
permissions: []
|
||||
}
|
||||
)
|
||||
dispatch('close', _id)
|
||||
|
||||
@@ -13,174 +13,230 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import card, { Role } from '@hcengineering/card'
|
||||
import contact, { Employee, UserRole } from '@hcengineering/contact'
|
||||
import { SelectUsersPopup, UserDetails } from '@hcengineering/contact-resources'
|
||||
import core, { Ref, WithLookup } from '@hcengineering/core'
|
||||
import presentation, { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import core, { Permission, Ref } from '@hcengineering/core'
|
||||
import { AttributeEditor, MessageBox, createQuery, getClient } from '@hcengineering/presentation'
|
||||
import {
|
||||
ButtonIcon,
|
||||
Icon,
|
||||
IconDelete,
|
||||
IconEdit,
|
||||
IconSettings,
|
||||
Label,
|
||||
Scroller,
|
||||
getCurrentResolvedLocation,
|
||||
navigate,
|
||||
showPopup
|
||||
} from '@hcengineering/ui'
|
||||
import contact from '@hcengineering/contact'
|
||||
import { ObjectBoxPopup } from '@hcengineering/view-resources'
|
||||
|
||||
import cardPlugin from '../../plugin'
|
||||
import { MasterTag, Role } from '@hcengineering/card'
|
||||
import settingRes from '@hcengineering/setting-resources/src/plugin'
|
||||
import { clearSettingsStore } from '@hcengineering/setting-resources'
|
||||
import { ButtonIcon, Icon, IconAdd, IconDelete, Modal, ModernButton, Scroller, showPopup } from '@hcengineering/ui'
|
||||
|
||||
export let _id: Ref<Role>
|
||||
export let masterTag: MasterTag
|
||||
export let readonly: boolean = false
|
||||
|
||||
const client = getClient()
|
||||
const h = client.getHierarchy()
|
||||
|
||||
const query = createQuery()
|
||||
let role: Role | undefined
|
||||
query.query(card.class.Role, { _id }, (res) => {
|
||||
role = res[0]
|
||||
const cardPermissionsObjectClasses = client
|
||||
.getModel()
|
||||
.findAllSync(cardPlugin.class.PermissionObjectClass, {})
|
||||
.map((poc) => poc.objectClass)
|
||||
const tagDesc = h.getAncestors(masterTag._id)
|
||||
const allPermissions = client.getModel().findAllSync(core.class.Permission, {
|
||||
scope: 'space',
|
||||
objectClass: { $in: [...cardPermissionsObjectClasses, ...tagDesc] }
|
||||
})
|
||||
$: name = role?.name
|
||||
|
||||
const usersQ = createQuery()
|
||||
let role: Role | undefined
|
||||
const roleQuery = createQuery()
|
||||
$: roleQuery.query(cardPlugin.class.Role, { _id }, (res) => {
|
||||
;[role] = res
|
||||
})
|
||||
|
||||
let roles: WithLookup<UserRole>[] = []
|
||||
let permissions: Permission[] = []
|
||||
$: permissions =
|
||||
role?.permissions !== undefined ? allPermissions.filter((p) => role?.permissions?.includes(p._id)) : []
|
||||
|
||||
usersQ.query(
|
||||
contact.class.UserRole,
|
||||
{ role: _id },
|
||||
(res) => {
|
||||
roles = res
|
||||
},
|
||||
{
|
||||
lookup: {
|
||||
user: contact.class.Person
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
let users: Employee[] = []
|
||||
$: users = roles.map((role) => role.$lookup?.user).filter((p) => p !== undefined)
|
||||
|
||||
async function remove (): Promise<void> {
|
||||
if (role === undefined) {
|
||||
function handleEditPermissions (evt: Event): void {
|
||||
if (role === undefined || readonly) {
|
||||
return
|
||||
}
|
||||
await client.remove(role)
|
||||
clearSettingsStore()
|
||||
}
|
||||
|
||||
async function removeAssignment (val: Ref<Employee>): Promise<void> {
|
||||
const toRemove = roles.filter((role) => role.user === val)
|
||||
for (const obj of toRemove) {
|
||||
await client.remove(obj)
|
||||
}
|
||||
}
|
||||
|
||||
function openSelectUsersPopup (): void {
|
||||
const selected = users.map((user) => user._id)
|
||||
showPopup(
|
||||
SelectUsersPopup,
|
||||
ObjectBoxPopup,
|
||||
{
|
||||
okLabel: presentation.string.Add,
|
||||
disableDeselectFor: selected,
|
||||
skipInactive: true,
|
||||
selected,
|
||||
showStatus: true
|
||||
_class: core.class.Permission,
|
||||
docQuery: { _id: { $in: allPermissions.map((p) => p._id) } },
|
||||
multiSelect: true,
|
||||
allowDeselect: true,
|
||||
selectedObjects: role.permissions
|
||||
},
|
||||
'top',
|
||||
(result?: Ref<Employee>[]) => {
|
||||
if (result != null) {
|
||||
void changeUsers(result)
|
||||
evt.target as HTMLElement,
|
||||
undefined,
|
||||
async (result) => {
|
||||
if (role === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
await client.updateCollection(
|
||||
cardPlugin.class.Role,
|
||||
core.space.Model,
|
||||
_id,
|
||||
cardPlugin.spaceType.SpaceType,
|
||||
core.class.SpaceType,
|
||||
'roles',
|
||||
{
|
||||
permissions: result
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
async function changeUsers (persons: Ref<Employee>[]): Promise<void> {
|
||||
const current = new Set(users.map((user) => user._id))
|
||||
const newPersons = persons.filter((person) => !current.has(person))
|
||||
if (newPersons.length === 0) {
|
||||
async function handleDeleteRole (): Promise<void> {
|
||||
showPopup(
|
||||
MessageBox,
|
||||
{
|
||||
label: settingRes.string.DeleteRole,
|
||||
message: settingRes.string.DeleteRoleConfirmation,
|
||||
action: async () => {
|
||||
await performDeleteRole()
|
||||
}
|
||||
},
|
||||
'top'
|
||||
)
|
||||
}
|
||||
|
||||
async function performDeleteRole (): Promise<void> {
|
||||
if (role === undefined) {
|
||||
return
|
||||
}
|
||||
const apply = client.apply()
|
||||
for (const person of newPersons) {
|
||||
await apply.createDoc(contact.class.UserRole, contact.space.Contacts, { role: _id, user: person })
|
||||
|
||||
const attribute = await client.findOne(core.class.Attribute, { name: _id, attributeOf: cardPlugin.class.CardSpace })
|
||||
const ops = client.apply()
|
||||
|
||||
await ops.removeCollection(
|
||||
cardPlugin.class.Role,
|
||||
core.space.Model,
|
||||
_id,
|
||||
role.attachedTo,
|
||||
role.attachedToClass,
|
||||
'roles'
|
||||
)
|
||||
if (attribute !== undefined) {
|
||||
const mixins = await client.findAll(cardPlugin.class.CardSpace, {})
|
||||
for (const mixin of mixins) {
|
||||
await ops.updateMixin(mixin._id, mixin._class, mixin.space, cardPlugin.class.CardSpace, {
|
||||
[attribute.name]: undefined
|
||||
})
|
||||
}
|
||||
|
||||
await ops.remove(attribute)
|
||||
}
|
||||
await apply.commit()
|
||||
|
||||
// remove all the assignments
|
||||
await ops.commit()
|
||||
|
||||
const loc = getCurrentResolvedLocation()
|
||||
loc.path.length = 5
|
||||
|
||||
clearSettingsStore()
|
||||
navigate(loc)
|
||||
}
|
||||
</script>
|
||||
|
||||
<Modal
|
||||
label={core.string.Role}
|
||||
type={'type-aside'}
|
||||
showCancelButton={false}
|
||||
canSave={true}
|
||||
okLabel={presentation.string.Close}
|
||||
okAction={clearSettingsStore}
|
||||
>
|
||||
<svelte:fragment slot="actions">
|
||||
<ButtonIcon icon={IconDelete} size={'small'} kind={'tertiary'} on:click={remove} />
|
||||
</svelte:fragment>
|
||||
<div class="hulyModal-content__titleGroup">
|
||||
<div class="flex fs-title items-center flex-gap-2">
|
||||
<Icon icon={contact.icon.Person} size={'medium'} />
|
||||
<div>
|
||||
{name}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hulyModal-content__settingsSet">
|
||||
<div class="item" style:padding="var(--spacing-1_5)" class:withoutBorder={users.length === 0}>
|
||||
<ModernButton
|
||||
label={presentation.string.Add}
|
||||
icon={IconAdd}
|
||||
iconSize="small"
|
||||
kind="secondary"
|
||||
size="small"
|
||||
on:click={openSelectUsersPopup}
|
||||
/>
|
||||
</div>
|
||||
{#each users as user, index (user._id)}
|
||||
<div class="item" class:withoutBorder={index === users.length - 1}>
|
||||
<div class="item__content">
|
||||
<UserDetails person={user} showStatus />
|
||||
<div class="item__action">
|
||||
<ButtonIcon
|
||||
icon={IconDelete}
|
||||
size="small"
|
||||
on:click={async () => {
|
||||
await removeAssignment(user._id)
|
||||
}}
|
||||
/>
|
||||
{#if role !== undefined}
|
||||
<div class="hulyComponent-content__container columns">
|
||||
<div class="hulyComponent-content__column content">
|
||||
<Scroller align={'center'} padding={'var(--spacing-3)'} bottomPadding={'var(--spacing-3)'}>
|
||||
<div class="hulyComponent-content gap">
|
||||
<div class="hulyComponent-content__column-group mt-4">
|
||||
<div class="hulyComponent-content__header mb-6 gap-2">
|
||||
<ButtonIcon
|
||||
icon={IconDelete}
|
||||
size="large"
|
||||
kind="secondary"
|
||||
disabled={readonly}
|
||||
on:click={handleDeleteRole}
|
||||
/>
|
||||
<ButtonIcon
|
||||
icon={contact.icon.Person}
|
||||
size="large"
|
||||
iconProps={{ size: 'small' }}
|
||||
kind="secondary"
|
||||
disabled={readonly}
|
||||
/>
|
||||
<div class="name" class:editable={!readonly}>
|
||||
<AttributeEditor
|
||||
_class={core.class.Role}
|
||||
object={role}
|
||||
key="name"
|
||||
editKind="modern-ghost-large"
|
||||
editable={!readonly}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hulyTableAttr-container">
|
||||
<div class="hulyTableAttr-header font-medium-12">
|
||||
<IconSettings size="small" />
|
||||
<span><Label label={settingRes.string.Permissions} /></span>
|
||||
<ButtonIcon
|
||||
kind="primary"
|
||||
icon={IconEdit}
|
||||
size="small"
|
||||
on:click={handleEditPermissions}
|
||||
disabled={readonly}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{#if permissions.length > 0}
|
||||
<div class="hulyTableAttr-content task">
|
||||
{#each permissions as permission}
|
||||
<div class="hulyTableAttr-content__row">
|
||||
{#if permission.icon !== undefined}
|
||||
<div class="hulyTableAttr-content__row-icon-wrapper">
|
||||
<Icon icon={permission.icon} size="small" />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="hulyTableAttr-content__row-label font-medium-14">
|
||||
<Label label={permission.label} />
|
||||
</div>
|
||||
|
||||
{#if permission.description !== undefined}
|
||||
<div class="hulyTableAttr-content__row-label grow dark font-regular-14">
|
||||
<Label label={permission.description} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</Scroller>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
.item {
|
||||
padding: var(--spacing-0_75);
|
||||
.name {
|
||||
width: 100%;
|
||||
font-weight: 500;
|
||||
margin-left: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 1.5rem;
|
||||
|
||||
&.withoutBorder {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.item__content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: var(--spacing-0_75);
|
||||
border-radius: var(--small-BorderRadius);
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background: var(--global-ui-highlight-BackgroundColor);
|
||||
|
||||
.item__action {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item__action {
|
||||
visibility: hidden;
|
||||
|
||||
&:hover {
|
||||
visibility: visible;
|
||||
}
|
||||
&.editable {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -17,9 +17,8 @@
|
||||
import contact from '@hcengineering/contact'
|
||||
import core from '@hcengineering/core'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { clearSettingsStore, settingsStore } from '@hcengineering/setting-resources'
|
||||
import { ButtonIcon, Icon, IconAdd, Label, showPopup } from '@hcengineering/ui'
|
||||
import { onDestroy } from 'svelte'
|
||||
import { clearSettingsStore } from '@hcengineering/setting-resources'
|
||||
import { ButtonIcon, getCurrentResolvedLocation, Icon, IconAdd, Label, navigate, showPopup } from '@hcengineering/ui'
|
||||
import card from '../../plugin'
|
||||
import CreateRolePopup from './CreateRolePopup.svelte'
|
||||
|
||||
@@ -29,26 +28,29 @@
|
||||
|
||||
const ancestors = client.getHierarchy().getAncestors(masterTag._id)
|
||||
|
||||
let roles = client.getModel().findAllSync(card.class.Role, { attachedTo: { $in: ancestors } })
|
||||
let roles = client.getModel().findAllSync(card.class.Role, { type: { $in: ancestors } })
|
||||
const query = createQuery()
|
||||
query.query(card.class.Role, { attachedTo: { $in: ancestors } }, (res) => {
|
||||
query.query(card.class.Role, { type: { $in: ancestors } }, (res) => {
|
||||
roles = res
|
||||
})
|
||||
|
||||
function addRole (): void {
|
||||
showPopup(CreateRolePopup, { masterTag }, undefined, (res) => {
|
||||
if (res != null) {
|
||||
$settingsStore = { id: res, component: card.component.EditRole, props: { _id: res } }
|
||||
}
|
||||
})
|
||||
showPopup(CreateRolePopup, { masterTag })
|
||||
}
|
||||
|
||||
const handleSelect = (role: Role): void => {
|
||||
$settingsStore = { id: role._id, component: card.component.EditRole, props: { _id: role._id } }
|
||||
}
|
||||
onDestroy(() => {
|
||||
const loc = getCurrentResolvedLocation()
|
||||
if (role?._id !== undefined) {
|
||||
loc.path[5] = card.component.EditRole
|
||||
loc.path[6] = role._id
|
||||
loc.path.length = 7
|
||||
} else {
|
||||
loc.path.length = 5
|
||||
}
|
||||
|
||||
clearSettingsStore()
|
||||
})
|
||||
navigate(loc)
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="hulyTableAttr-header font-medium-12">
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
//
|
||||
|
||||
import card, { cardId } from '@hcengineering/card'
|
||||
import { type Doc, type Ref } from '@hcengineering/core'
|
||||
import { type Permission, type Doc, type Ref } from '@hcengineering/core'
|
||||
import { type IntlString, mergeIds, type Resource } from '@hcengineering/platform'
|
||||
import { type ObjectSearchCategory, type ObjectSearchFactory } from '@hcengineering/presentation'
|
||||
import { type AnyComponent } from '@hcengineering/ui/src/types'
|
||||
@@ -58,6 +58,18 @@ export default mergeIds(cardId, card, {
|
||||
function: {
|
||||
CardFactory: '' as Resource<(props?: Record<string, any>) => Promise<Ref<Doc> | undefined>>
|
||||
},
|
||||
permission: {
|
||||
CreateCard: '' as Ref<Permission>,
|
||||
RemoveCard: '' as Ref<Permission>,
|
||||
UpdateCard: '' as Ref<Permission>,
|
||||
AddTag: '' as Ref<Permission>,
|
||||
RemoveTag: '' as Ref<Permission>,
|
||||
ForbidCreateCard: '' as Ref<Permission>,
|
||||
ForbidRemoveCard: '' as Ref<Permission>,
|
||||
ForbidUpdateCard: '' as Ref<Permission>,
|
||||
ForbidAddTag: '' as Ref<Permission>,
|
||||
ForbidRemoveTag: '' as Ref<Permission>
|
||||
},
|
||||
sectionComponent: {
|
||||
AttachmentsSection: '' as AnyComponent,
|
||||
ChildrenSection: '' as AnyComponent,
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
import {
|
||||
AttachedDoc,
|
||||
Role as BaseRole,
|
||||
Blobs,
|
||||
Class,
|
||||
CollectionSize,
|
||||
@@ -23,11 +23,13 @@ import {
|
||||
Mixin,
|
||||
Rank,
|
||||
Ref,
|
||||
Space
|
||||
Space,
|
||||
SpaceType,
|
||||
TypedSpace
|
||||
} from '@hcengineering/core'
|
||||
import { Asset, IntlString, plugin, Plugin, Resource } from '@hcengineering/platform'
|
||||
import type { AnyComponent, ComponentExtensionId } from '@hcengineering/ui'
|
||||
import { Preference } from '@hcengineering/preference'
|
||||
import type { AnyComponent, ComponentExtensionId } from '@hcengineering/ui'
|
||||
import { IconProps } from '@hcengineering/view'
|
||||
|
||||
export * from './analytics'
|
||||
@@ -41,9 +43,8 @@ export interface MasterTag extends Class<Card> {
|
||||
|
||||
export interface Tag extends MasterTag, Mixin<Card> {}
|
||||
|
||||
export interface Role extends AttachedDoc<MasterTag | Tag, 'roles'> {
|
||||
name: string
|
||||
attachedTo: Ref<MasterTag | Tag>
|
||||
export interface Role extends BaseRole {
|
||||
type: Ref<MasterTag | Tag>
|
||||
}
|
||||
|
||||
export interface Card extends Doc, IconProps {
|
||||
@@ -61,7 +62,7 @@ export interface Card extends Doc, IconProps {
|
||||
peerId?: string
|
||||
}
|
||||
|
||||
export interface CardSpace extends Space {
|
||||
export interface CardSpace extends TypedSpace {
|
||||
types: Ref<MasterTag>[]
|
||||
}
|
||||
|
||||
@@ -111,6 +112,10 @@ export interface CreateCardExtension extends MasterTag {
|
||||
hideSpace?: boolean
|
||||
}
|
||||
|
||||
export interface PermissionObjectClass extends Doc {
|
||||
objectClass: Ref<Class<Doc>>
|
||||
}
|
||||
|
||||
export type CanCreateCardFn = (space: Ref<Space>, data: Partial<Data<Card>>) => Promise<boolean | Ref<Card>>
|
||||
export type CanCreateCardResource = Resource<CanCreateCardFn>
|
||||
|
||||
@@ -134,7 +139,8 @@ const cardPlugin = plugin(cardId, {
|
||||
Role: '' as Ref<Class<Role>>,
|
||||
CardSection: '' as Ref<Class<CardSection>>,
|
||||
FavoriteCard: '' as Ref<Class<FavoriteCard>>,
|
||||
FavoriteType: '' as Ref<Class<FavoriteType>>
|
||||
FavoriteType: '' as Ref<Class<FavoriteType>>,
|
||||
PermissionObjectClass: '' as Ref<Class<PermissionObjectClass>>
|
||||
},
|
||||
mixin: {
|
||||
CardViewDefaults: '' as Ref<Mixin<CardViewDefaults>>,
|
||||
@@ -143,6 +149,9 @@ const cardPlugin = plugin(cardId, {
|
||||
space: {
|
||||
Default: '' as Ref<CardSpace>
|
||||
},
|
||||
spaceType: {
|
||||
SpaceType: '' as Ref<SpaceType>
|
||||
},
|
||||
types: {
|
||||
File: '' as Ref<MasterTag>,
|
||||
Document: '' as Ref<MasterTag>
|
||||
|
||||
@@ -268,7 +268,6 @@
|
||||
"EditDocumentSpace": "Upravit prostor dokumentů",
|
||||
"DocSpaceDescriptionPlaceholder": "Popište svůj prostor...",
|
||||
"Members": "Členové",
|
||||
"RoleLabel": "Role: {role}",
|
||||
"CreateOrgSpace": "Vytvořit prostor organizace",
|
||||
"ReviewDocumentPermission": "Revidovat dokument",
|
||||
"ReviewDocumentDescription": "Uděluje uživatelům možnost revidovat dokument",
|
||||
|
||||
@@ -274,7 +274,6 @@
|
||||
|
||||
"DocSpaceDescriptionPlaceholder": "Beschreiben Sie Ihren Bereich...",
|
||||
"Members": "Mitglieder",
|
||||
"RoleLabel": "Rolle: {role}",
|
||||
"CreateOrgSpace": "Organisationsbereich erstellen",
|
||||
|
||||
"ReviewDocumentPermission": "Dokument prüfen",
|
||||
|
||||
@@ -281,7 +281,6 @@
|
||||
|
||||
"DocSpaceDescriptionPlaceholder": "Describe your space...",
|
||||
"Members": "Members",
|
||||
"RoleLabel": "Role: {role}",
|
||||
"CreateOrgSpace": "Create organisation space",
|
||||
|
||||
"ReviewDocumentPermission": "Review document",
|
||||
|
||||
@@ -236,7 +236,7 @@
|
||||
"EditDocumentSpace": "Modifier l'espace de documents",
|
||||
"DocSpaceDescriptionPlaceholder": "Décrivez votre espace...",
|
||||
"Members": "Membres",
|
||||
"RoleLabel": "Rôle : {role}",
|
||||
"": "Rôle : {role}",
|
||||
"CreateOrgSpace": "Créer un espace organisationnel",
|
||||
"ReviewDocumentPermission": "Réviser le document",
|
||||
"ReviewDocumentDescription": "Accorde aux utilisateurs la capacité de réviser un document",
|
||||
|
||||
@@ -234,7 +234,6 @@
|
||||
"EditDocumentSpace": "Modifica spazio documenti",
|
||||
"DocSpaceDescriptionPlaceholder": "Descrivi il tuo spazio...",
|
||||
"Members": "Membri",
|
||||
"RoleLabel": "Ruolo: {role}",
|
||||
"CreateOrgSpace": "Crea spazio organizzativo",
|
||||
"ReviewDocumentPermission": "Revisiona documento",
|
||||
"ReviewDocumentDescription": "Concede agli utenti la possibilità di revisionare un documento",
|
||||
|
||||
@@ -239,7 +239,6 @@
|
||||
"EditDocumentSpace": "ドキュメントスペースを編集",
|
||||
"DocSpaceDescriptionPlaceholder": "スペースの説明...",
|
||||
"Members": "メンバー",
|
||||
"RoleLabel": "役割: {role}",
|
||||
"CreateOrgSpace": "組織スペースを作成",
|
||||
"ReviewDocumentPermission": "ドキュメントをレビュー",
|
||||
"ReviewDocumentDescription": "ユーザーにドキュメントをレビューする権限を付与します",
|
||||
|
||||
@@ -276,7 +276,6 @@
|
||||
|
||||
"DocSpaceDescriptionPlaceholder": "Опишите Ваше пространство...",
|
||||
"Members": "Участники",
|
||||
"RoleLabel": "Роль: {role}",
|
||||
"CreateOrgSpace": "Создать пространство организации",
|
||||
|
||||
"ReviewDocumentPermission": "Рецензировать документ",
|
||||
|
||||
@@ -239,7 +239,6 @@
|
||||
"EditDocumentSpace": "Doküman alanını düzenle",
|
||||
"DocSpaceDescriptionPlaceholder": "Alanınızı açıklayın...",
|
||||
"Members": "Üyeler",
|
||||
"RoleLabel": "Rol: {role}",
|
||||
"CreateOrgSpace": "Organizasyon alanı oluştur",
|
||||
"ReviewDocumentPermission": "Dokümanı incele",
|
||||
"ReviewDocumentDescription": "Kullanıcılara doküman inceleme yetkisi verir",
|
||||
|
||||
@@ -273,7 +273,6 @@
|
||||
|
||||
"DocSpaceDescriptionPlaceholder": "描述您的空间...",
|
||||
"Members": "成员",
|
||||
"RoleLabel": "角色:{role}",
|
||||
"CreateOrgSpace": "创建组织空间",
|
||||
|
||||
"ReviewDocumentPermission": "审查文档",
|
||||
|
||||
+2
-1
@@ -36,6 +36,7 @@
|
||||
import documents, { DocumentSpace, DocumentSpaceType } from '@hcengineering/controlled-documents'
|
||||
|
||||
import documentsRes from '../../plugin'
|
||||
import view from '@hcengineering/view'
|
||||
|
||||
export let docSpace: DocumentSpace | undefined = undefined
|
||||
export let clazz: Ref<Class<DocumentSpace>> = documents.class.OrgSpace
|
||||
@@ -315,7 +316,7 @@
|
||||
{#each roles as role}
|
||||
<div class="antiGrid-row">
|
||||
<div class="antiGrid-row__header">
|
||||
<Label label={documentsRes.string.RoleLabel} params={{ role: role.name }} />
|
||||
<Label label={view.string.RoleLabel} params={{ role: role.name }} />
|
||||
</div>
|
||||
<AccountArrayEditor
|
||||
value={rolesAssignment?.[role._id] ?? []}
|
||||
|
||||
@@ -209,7 +209,6 @@ export default mergeIds(documentsId, documents, {
|
||||
EditDocumentSpace: '' as IntlString,
|
||||
DocSpaceDescriptionPlaceholder: '' as IntlString,
|
||||
Members: '' as IntlString,
|
||||
RoleLabel: '' as IntlString,
|
||||
|
||||
ViewAll: '' as IntlString,
|
||||
Readonly: '' as IntlString,
|
||||
|
||||
@@ -58,7 +58,6 @@
|
||||
|
||||
"Icon": "Ikona",
|
||||
"Color": "Barva",
|
||||
"RoleLabel": "Role: {role}",
|
||||
"ForbidCreateTeamspacePermission": "Zakázat vytvoření týmového prostoru",
|
||||
"ForbidCreateTeamspacePermissionDescription": "Zakazuje uživatelům vytvářet nové týmové prostory"
|
||||
}
|
||||
|
||||
@@ -51,7 +51,6 @@
|
||||
"ConfigDescription": "Erweiterung für kollaborative Dokumentbearbeitung",
|
||||
"Icon": "Symbol",
|
||||
"Color": "Farbe",
|
||||
"RoleLabel": "Rolle: {role}",
|
||||
"ForbidCreateTeamspacePermission": "Arbeitsbereichserstellung verbieten",
|
||||
"ForbidCreateTeamspacePermissionDescription": "Verbietet Benutzern das Erstellen neuer Arbeitsbereiche"
|
||||
}
|
||||
|
||||
@@ -58,7 +58,6 @@
|
||||
|
||||
"Icon": "Icon",
|
||||
"Color": "Color",
|
||||
"RoleLabel": "Role: {role}",
|
||||
"ForbidCreateTeamspacePermission": "Forbid create teamspace",
|
||||
"ForbidCreateTeamspacePermissionDescription": "Forbid users creating new teamspaces"
|
||||
}
|
||||
|
||||
@@ -51,7 +51,6 @@
|
||||
"ConfigDescription": "Extensión para edición colaborativo de documentos",
|
||||
"Icon": "Icono",
|
||||
"Color": "Color",
|
||||
"RoleLabel": "Role: {role}",
|
||||
"ForbidCreateTeamspacePermission": "Prohibir crear espacio de trabajo",
|
||||
"ForbidCreateTeamspacePermissionDescription": "Prohíbe a los usuarios crear nuevos espacios de trabajo"
|
||||
}
|
||||
|
||||
@@ -51,7 +51,6 @@
|
||||
"ConfigDescription": "Extension pour l'édition collaborative de documents",
|
||||
"Icon": "Icône",
|
||||
"Color": "Couleur",
|
||||
"RoleLabel": "Rôle : {role}",
|
||||
"ForbidCreateTeamspacePermission": "Interdire la création d'espace d'équipe",
|
||||
"ForbidCreateTeamspacePermissionDescription": "Interdit aux utilisateurs de créer de nouveaux espaces d'équipe"
|
||||
}
|
||||
|
||||
@@ -51,7 +51,6 @@
|
||||
"ConfigDescription": "Estensione per la modifica collaborativa dei documenti",
|
||||
"Icon": "Icona",
|
||||
"Color": "Colore",
|
||||
"RoleLabel": "Ruolo: {role}",
|
||||
"ForbidCreateTeamspacePermission": "Vieta creazione teamspace",
|
||||
"ForbidCreateTeamspacePermissionDescription": "Vieta agli utenti di creare nuovi teamspaces"
|
||||
}
|
||||
|
||||
@@ -51,7 +51,6 @@
|
||||
"ConfigDescription": "共同ドキュメント編集のための拡張機能",
|
||||
"Icon": "アイコン",
|
||||
"Color": "色",
|
||||
"RoleLabel": "ロール: {role}",
|
||||
"ForbidCreateTeamspacePermission": "チームスペースの作成禁止",
|
||||
"ForbidCreateTeamspacePermissionDescription": "ユーザーが新しいチームスペースを作成することを禁止します"
|
||||
}
|
||||
|
||||
@@ -51,7 +51,6 @@
|
||||
"ConfigDescription": "Extensão para edição colaborativa de documentos",
|
||||
"Icon": "Ícone",
|
||||
"Color": "Cor",
|
||||
"RoleLabel": "Papel: {role}",
|
||||
"ForbidCreateTeamspacePermission": "Proibir criação de espaço de trabalho",
|
||||
"ForbidCreateTeamspacePermissionDescription": "Proíbe os utilizadores de criar novos espaços de trabalho"
|
||||
}
|
||||
|
||||
@@ -58,7 +58,6 @@
|
||||
|
||||
"Icon": "Иконка",
|
||||
"Color": "Цвет",
|
||||
"RoleLabel": "Роль: {role}",
|
||||
"ForbidCreateTeamspacePermission": "Запретить создание пространства",
|
||||
"ForbidCreateTeamspacePermissionDescription": "Запрещает пользователям создавать новые пространства"
|
||||
}
|
||||
|
||||
@@ -50,7 +50,6 @@
|
||||
"ConfigLabel": "Dokümanlar",
|
||||
"ConfigDescription": "İşbirlikli doküman düzenleme için uzantı",
|
||||
"Icon": "İkon",
|
||||
"Color": "Renk",
|
||||
"RoleLabel": "Rol: {role}"
|
||||
"Color": "Renk"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,6 @@
|
||||
"ReassignToDoConfirm": "您要更改待办事项被指派人吗?待办事项将从当前被指派人的计划中移除。",
|
||||
"Icon": "图标",
|
||||
"Color": "颜色",
|
||||
"RoleLabel": "角色:{role}",
|
||||
"ForbidCreateTeamspacePermission": "禁止创建团队空间",
|
||||
"ForbidCreateTeamspacePermissionDescription": "禁止用户创建新团队空间"
|
||||
}
|
||||
|
||||
@@ -417,7 +417,7 @@
|
||||
{#each roles as role}
|
||||
<div class="antiGrid-row">
|
||||
<div class="antiGrid-row__header">
|
||||
<Label label={documentRes.string.RoleLabel} params={{ role: role.name }} />
|
||||
<Label label={view.string.RoleLabel} params={{ role: role.name }} />
|
||||
</div>
|
||||
<AccountArrayEditor
|
||||
value={rolesAssignment?.[role._id] ?? []}
|
||||
|
||||
@@ -87,8 +87,6 @@ export default mergeIds(documentId, document, {
|
||||
CompareTo: '' as IntlString,
|
||||
|
||||
Color: '' as IntlString,
|
||||
Icon: '' as IntlString,
|
||||
|
||||
RoleLabel: '' as IntlString
|
||||
Icon: '' as IntlString
|
||||
}
|
||||
})
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
"EditDrive": "Upravit disk",
|
||||
"Rename": "Přejmenovat",
|
||||
"Restore": "Obnovit",
|
||||
"RoleLabel": "Role",
|
||||
"Root": "/",
|
||||
"ForbidCreateDrivePermission": "Zakázat vytvoření disku",
|
||||
"ForbidCreateDrivePermissionDescription": "Zakazuje uživatelům vytvářet nové disky"
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
"EditDrive": "Laufwerk bearbeiten",
|
||||
"Rename": "Umbenennen",
|
||||
"Restore": "Wiederherstellen",
|
||||
"RoleLabel": "Rolle",
|
||||
"Root": "/",
|
||||
"ForbidCreateDrivePermission": "Laufwerkserstellung verbieten",
|
||||
"ForbidCreateDrivePermissionDescription": "Verbietet Benutzern die Erstellung neuer Laufwerke"
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
"EditDrive": "Edit Drive",
|
||||
"Rename": "Rename",
|
||||
"Restore": "Restore",
|
||||
"RoleLabel": "Role",
|
||||
"Root": "/",
|
||||
"ForbidCreateDrivePermission": "Forbid create drive",
|
||||
"ForbidCreateDrivePermissionDescription": "Forbid users creating new drives"
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
"EditDrive": "Editar unidad",
|
||||
"Rename": "Renombrar",
|
||||
"Restore": "Restaurar",
|
||||
"RoleLabel": "Rol",
|
||||
"Root": "/",
|
||||
"ForbidCreateDrivePermission": "Prohibir crear unidad",
|
||||
"ForbidCreateDrivePermissionDescription": "Prohíbe a los usuarios crear nuevas unidades"
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
"EditDrive": "Modifier le disque",
|
||||
"Rename": "Renommer",
|
||||
"Restore": "Restaurer",
|
||||
"RoleLabel": "Rôle",
|
||||
"Root": "/",
|
||||
"ForbidCreateDrivePermission": "Interdire la création de disque",
|
||||
"ForbidCreateDrivePermissionDescription": "Interdit aux utilisateurs de créer de nouveaux disques"
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
"EditDrive": "Modifica drive",
|
||||
"Rename": "Rinomina",
|
||||
"Restore": "Ripristina",
|
||||
"RoleLabel": "Ruolo",
|
||||
"Root": "/",
|
||||
"ForbidCreateDrivePermission": "Vieta creazione drive",
|
||||
"ForbidCreateDrivePermissionDescription": "Vieta agli utenti di creare nuovi drive"
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
"EditDrive": "ドライブを編集",
|
||||
"Rename": "名前を変更",
|
||||
"Restore": "復元",
|
||||
"RoleLabel": "ロール",
|
||||
"Root": "/",
|
||||
"ForbidCreateDrivePermission": "ドライブの作成禁止",
|
||||
"ForbidCreateDrivePermissionDescription": "ユーザーが新しいドライブを作成することを禁止します"
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
"EditDrive": "Editar unidade",
|
||||
"Rename": "Renomear",
|
||||
"Restore": "Restaurar",
|
||||
"RoleLabel": "Papel",
|
||||
"Root": "/",
|
||||
"ForbidCreateDrivePermission": "Proibir criação de unidade",
|
||||
"ForbidCreateDrivePermissionDescription": "Proíbe os utilizadores de criar novas unidades"
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
"EditDrive": "Редактировать",
|
||||
"Rename": "Переименовать",
|
||||
"Restore": "Восстановить",
|
||||
"RoleLabel": "Роль",
|
||||
"Root": "/",
|
||||
"ForbidCreateDrivePermission": "Запретить создание диска",
|
||||
"ForbidCreateDrivePermissionDescription": "Запрещает пользователям создавать новые диски"
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
"EditDrive": "Sürücüyü Düzenle",
|
||||
"Rename": "Yeniden adlandır",
|
||||
"Restore": "Geri yükle",
|
||||
"RoleLabel": "Rol",
|
||||
"Root": "/"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
"EditDrive": "编辑磁盘",
|
||||
"Rename": "重命名",
|
||||
"Restore": "恢复",
|
||||
"RoleLabel": "角色",
|
||||
"Root": "/",
|
||||
"ForbidCreateDrivePermission": "禁止创建磁盘",
|
||||
"ForbidCreateDrivePermissionDescription": "禁止用户创建新磁盘"
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
|
||||
import driveRes from '../plugin'
|
||||
import { Analytics } from '@hcengineering/analytics'
|
||||
import view from '@hcengineering/view'
|
||||
|
||||
export let drive: Drive | undefined = undefined
|
||||
|
||||
@@ -309,7 +310,7 @@
|
||||
{#each roles as role}
|
||||
<div class="antiGrid-row">
|
||||
<div class="antiGrid-row__header">
|
||||
<Label label={driveRes.string.RoleLabel} params={{ role: role.name }} />
|
||||
<Label label={view.string.RoleLabel} params={{ role: role.name }} />
|
||||
</div>
|
||||
<AccountArrayEditor
|
||||
value={rolesAssignment?.[role._id] ?? []}
|
||||
|
||||
@@ -25,7 +25,6 @@ export default mergeIds(driveId, drive, {
|
||||
Upload: '' as IntlString,
|
||||
EditDrive: '' as IntlString,
|
||||
Rename: '' as IntlString,
|
||||
RoleLabel: '' as IntlString,
|
||||
Root: '' as IntlString,
|
||||
FileVersions: '' as IntlString
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
"ConfigDescription": "Rozšíření pro řízení vztahů se zákazníky",
|
||||
"EditFunnel": "Upravit trychtýř",
|
||||
"FunnelMembers": "Členové",
|
||||
"RoleLabel": "Role: {role}",
|
||||
"ForbidCreateFunnelPermission": "Zakázat vytvoření trychtýře",
|
||||
"ForbidCreateFunnelPermissionDescription": "Zakazuje uživatelům vytvářet nové trychtýře"
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
"ConfigDescription": "Erweiterung für Customer Relationship Management",
|
||||
"EditFunnel": "Trichter bearbeiten",
|
||||
"FunnelMembers": "Mitglieder",
|
||||
"RoleLabel": "Rolle: {role}",
|
||||
"ForbidCreateFunnelPermission": "Trichtererstellung verbieten",
|
||||
"ForbidCreateFunnelPermissionDescription": "Verbietet Benutzern das Erstellen neuer Trichter"
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
"ConfigDescription": "Extension for Customer relation management",
|
||||
"EditFunnel": "Edit Funnel",
|
||||
"FunnelMembers": "Members",
|
||||
"RoleLabel": "Role: {role}",
|
||||
"ForbidCreateFunnelPermission": "Forbid create funnel",
|
||||
"ForbidCreateFunnelPermissionDescription": "Forbid users creating new funnels"
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
"ConfigDescription": "Extensión para la gestión de las relaciones con los Clientes",
|
||||
"EditFunnel": "Editar Embudo",
|
||||
"FunnelMembers": "Miembros",
|
||||
"RoleLabel": "Role: {role}",
|
||||
"ForbidCreateFunnelPermission": "Prohibir crear embudo",
|
||||
"ForbidCreateFunnelPermissionDescription": "Prohíbe a los usuarios crear nuevos embudos"
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
"ConfigDescription": "Extension pour la gestion de la relation client",
|
||||
"EditFunnel": "Modifier le pipeline",
|
||||
"FunnelMembers": "Membres",
|
||||
"RoleLabel": "Rôle : {role}",
|
||||
"ForbidCreateFunnelPermission": "Interdire la création de pipeline",
|
||||
"ForbidCreateFunnelPermissionDescription": "Interdit aux utilisateurs de créer de nouveaux pipelines"
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
"ConfigDescription": "Estensione per la gestione delle relazioni con i clienti",
|
||||
"EditFunnel": "Modifica Funnel",
|
||||
"FunnelMembers": "Membri",
|
||||
"RoleLabel": "Ruolo: {role}",
|
||||
"ForbidCreateFunnelPermission": "Vieta creazione funnel",
|
||||
"ForbidCreateFunnelPermissionDescription": "Vieta agli utenti di creare nuovi funnel"
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
"ConfigDescription": "顧客関係管理のための拡張機能",
|
||||
"EditFunnel": "ファネルを編集",
|
||||
"FunnelMembers": "メンバー",
|
||||
"RoleLabel": "ロール: {role}",
|
||||
"ForbidCreateFunnelPermission": "ファネルの作成禁止",
|
||||
"ForbidCreateFunnelPermissionDescription": "ユーザーが新しいファネルを作成することを禁止します"
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
"ConfigDescription": "Extensão para gestão de relacionamento com o Cliente",
|
||||
"EditFunnel": "Editar Funil",
|
||||
"FunnelMembers": "Membros",
|
||||
"RoleLabel": "Cargo: {role}",
|
||||
"ForbidCreateFunnelPermission": "Proibir criação de funil",
|
||||
"ForbidCreateFunnelPermissionDescription": "Proíbe os utilizadores de criar novos funis"
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
"ConfigDescription": "Расширение по работе с клиентами",
|
||||
"EditFunnel": "Редактировать воронку",
|
||||
"FunnelMembers": "Участники",
|
||||
"RoleLabel": "Роль: {role}",
|
||||
"ForbidCreateFunnelPermission": "Запретить создание воронки",
|
||||
"ForbidCreateFunnelPermissionDescription": "Запрещает пользователям создавать новые воронки"
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
"ConfigLabel": "CRM",
|
||||
"ConfigDescription": "Müşteri ilişkiler yönetimi için uzantı",
|
||||
"EditFunnel": "Huniyi Düzenle",
|
||||
"FunnelMembers": "Üyeler",
|
||||
"RoleLabel": "Rol: {role}"
|
||||
"FunnelMembers": "Üyeler"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
"ConfigDescription": "用于客户关系管理的扩展",
|
||||
"EditFunnel": "编辑漏斗",
|
||||
"FunnelMembers": "成员",
|
||||
"RoleLabel": "角色:{role}",
|
||||
"ForbidCreateFunnelPermission": "禁止创建漏斗",
|
||||
"ForbidCreateFunnelPermissionDescription": "禁止用户创建新漏斗"
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
import leadRes from '../plugin'
|
||||
import { Analytics } from '@hcengineering/analytics'
|
||||
import view from '@hcengineering/view'
|
||||
|
||||
export let funnel: Funnel | undefined = undefined
|
||||
const dispatch = createEventDispatcher()
|
||||
@@ -260,7 +261,7 @@
|
||||
{#each roles as role}
|
||||
<div class="antiGrid-row">
|
||||
<div class="antiGrid-row__header">
|
||||
<Label label={leadRes.string.RoleLabel} params={{ role: role.name }} />
|
||||
<Label label={view.string.RoleLabel} params={{ role: role.name }} />
|
||||
</div>
|
||||
<AccountArrayEditor
|
||||
value={rolesAssignment?.[role._id] ?? []}
|
||||
|
||||
@@ -44,7 +44,6 @@ export default mergeIds(leadId, lead, {
|
||||
Assignee: '' as IntlString,
|
||||
UnAssign: '' as IntlString,
|
||||
FunnelMembers: '' as IntlString,
|
||||
RoleLabel: '' as IntlString,
|
||||
EditFunnel: '' as IntlString
|
||||
},
|
||||
component: {
|
||||
|
||||
@@ -117,7 +117,11 @@
|
||||
"Filter": "Filtr",
|
||||
"FirstMatchValue": "První odpovídající hodnota",
|
||||
"ConfigLabel": "Konfigurace procesů",
|
||||
"ConfigDescription": "Definujte procesy pro automatizaci pracovních postupů a obchodních procesů."
|
||||
"ConfigDescription": "Definujte procesy pro automatizaci pracovních postupů a obchodních procesů.",
|
||||
"RunProcessPermission": "Spustit proces",
|
||||
"CancelProcessPermission": "Zrušit proces",
|
||||
"ForbidRunProcessPermission": "Zakázat spuštění procesu",
|
||||
"ForbidCancelProcessPermission": "Zakázat zrušení procesu"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Metoda nenalezena: {methodId}",
|
||||
|
||||
@@ -117,7 +117,11 @@
|
||||
"Filter": "Filter",
|
||||
"FirstMatchValue": "Erster passender Wert",
|
||||
"ConfigLabel": "Prozesskonfiguration",
|
||||
"ConfigDescription": "Definieren Sie Prozesse, um Workflows und Geschäftsprozesse zu automatisieren."
|
||||
"ConfigDescription": "Definieren Sie Prozesse, um Workflows und Geschäftsprozesse zu automatisieren.",
|
||||
"RunProcessPermission": "Prozess ausführen",
|
||||
"CancelProcessPermission": "Prozess abbrechen",
|
||||
"ForbidRunProcessPermission": "Ausführen des Prozesses verbieten",
|
||||
"ForbidCancelProcessPermission": "Abbrechen des Prozesses verbieten"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Methode nicht gefunden: {methodId}",
|
||||
|
||||
@@ -122,7 +122,11 @@
|
||||
"Filter": "Filter",
|
||||
"FirstMatchValue": "First match value",
|
||||
"ConfigLabel": "Process configuration",
|
||||
"ConfigDescription": "Define processes to automate workflows and business processes."
|
||||
"ConfigDescription": "Define processes to automate workflows and business processes.",
|
||||
"RunProcessPermission": "Run process",
|
||||
"CancelProcessPermission": "Cancel process",
|
||||
"ForbidRunProcessPermission": "Forbid running process",
|
||||
"ForbidCancelProcessPermission": "Forbid cancelling process"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Method not found: {methodId}",
|
||||
|
||||
@@ -122,7 +122,11 @@
|
||||
"Filter": "Filtro",
|
||||
"FirstMatchValue": "Primer valor coincidente",
|
||||
"ConfigLabel": "Configuración de procesos",
|
||||
"ConfigDescription": "Defina procesos para automatizar flujos de trabajo y procesos comerciales."
|
||||
"ConfigDescription": "Defina procesos para automatizar flujos de trabajo y procesos comerciales.",
|
||||
"RunProcessPermission": "Ejecutar proceso",
|
||||
"CancelProcessPermission": "Cancelar proceso",
|
||||
"ForbidRunProcessPermission": "Prohibir ejecución de proceso",
|
||||
"ForbidCancelProcessPermission": "Prohibir cancelación de proceso"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Método no encontrado: {methodId}",
|
||||
|
||||
@@ -122,7 +122,11 @@
|
||||
"Filter": "Filtrer",
|
||||
"FirstMatchValue": "Première valeur correspondante",
|
||||
"ConfigLabel": "Configuration des processus",
|
||||
"ConfigDescription": "Définissez des processus pour automatiser les flux de travail et les processus métier."
|
||||
"ConfigDescription": "Définissez des processus pour automatiser les flux de travail et les processus métier.",
|
||||
"RunProcessPermission": "Exécuter le processus",
|
||||
"CancelProcessPermission": "Annuler le processus",
|
||||
"ForbidRunProcessPermission": "Interdire l'exécution du processus",
|
||||
"ForbidCancelProcessPermission": "Interdire l'annulation du processus"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Méthode introuvable : {methodId}",
|
||||
|
||||
@@ -121,8 +121,12 @@
|
||||
"ExecutionStarted": "Esecuzione avviata",
|
||||
"Filter": "Filtro",
|
||||
"FirstMatchValue": "Primo valore corrispondente",
|
||||
"ConfigLabel": "Configurazione dei processi",
|
||||
"ConfigDescription": "Definisci i processi per automatizzare i flussi di lavoro e i processi aziendali."
|
||||
"ConfigLabel": "Configurazione del processo",
|
||||
"ConfigDescription": "Definire i processi per automatizzare i flussi di lavoro e i processi aziendali.",
|
||||
"RunProcessPermission": "Esegui processo",
|
||||
"CancelProcessPermission": "Annulla processo",
|
||||
"ForbidRunProcessPermission": "Vieta l'esecuzione del processo",
|
||||
"ForbidCancelProcessPermission": "Vieta l'annullamento del processo"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Metodo non trovato: {methodId}",
|
||||
|
||||
@@ -121,7 +121,11 @@
|
||||
"Filter": "フィルター",
|
||||
"FirstMatchValue": "最初の一致する値",
|
||||
"ConfigLabel": "プロセス構成",
|
||||
"ConfigDescription": "ワークフローやビジネスプロセスを自動化するためのプロセスを定義します。"
|
||||
"ConfigDescription": "ワークフローやビジネスプロセスを自動化するためのプロセスを定義します。",
|
||||
"RunProcessPermission": "プロセスを実行",
|
||||
"CancelProcessPermission": "プロセスをキャンセル",
|
||||
"ForbidRunProcessPermission": "プロセスの実行を禁止",
|
||||
"ForbidCancelProcessPermission": "プロセスのキャンセルを禁止"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "メソッドが見つかりません: {methodId}",
|
||||
|
||||
@@ -122,7 +122,11 @@
|
||||
"Filter": "Filtrar",
|
||||
"FirstMatchValue": "Primeiro Valor Correspondente",
|
||||
"ConfigLabel": "Configuração de processos",
|
||||
"ConfigDescription": "Defina processos para automatizar fluxos de trabalho e processos de negócios."
|
||||
"ConfigDescription": "Defina processos para automatizar fluxos de trabalho e processos de negócios.",
|
||||
"RunProcessPermission": "Executar processo",
|
||||
"CancelProcessPermission": "Cancelar processo",
|
||||
"ForbidRunProcessPermission": "Proibir execução do processo",
|
||||
"ForbidCancelProcessPermission": "Proibir cancelamento do processo"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Método não encontrado: {methodId}",
|
||||
|
||||
@@ -122,7 +122,11 @@
|
||||
"Filter": "Фильтр",
|
||||
"FirstMatchValue": "Первое подходящее значение",
|
||||
"ConfigLabel": "Конфигурация процессов",
|
||||
"ConfigDescription": "Определяйте процессы для автоматизации рабочих процессов и бизнес-процессов."
|
||||
"ConfigDescription": "Определяйте процессы для автоматизации рабочих процессов и бизнес-процессов.",
|
||||
"RunProcessPermission": "Запустить процесс",
|
||||
"CancelProcessPermission": "Отменить процесс",
|
||||
"ForbidRunProcessPermission": "Запретить запуск процесса",
|
||||
"ForbidCancelProcessPermission": "Запретить отмену процесса"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Метод не найден: {methodId}",
|
||||
|
||||
@@ -119,7 +119,11 @@
|
||||
"Filter": "Filtre",
|
||||
"FirstMatchValue": "İlk eşleşen değer",
|
||||
"ConfigLabel": "Süreç yapılandırması",
|
||||
"ConfigDescription": "İş akışlarını ve iş süreçlerini otomatikleştirmek için süreçler tanımlayın."
|
||||
"ConfigDescription": "İş akışlarını ve iş süreçlerini otomatikleştirmek için süreçler tanımlayın.",
|
||||
"RunProcessPermission": "Süreci çalıştır",
|
||||
"CancelProcessPermission": "Süreci iptal et",
|
||||
"ForbidRunProcessPermission": "Süreci çalıştırmayı yasakla",
|
||||
"ForbidCancelProcessPermission": "Süreci iptal etmeyi yasakla"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Metod bulunamadı: {methodId}",
|
||||
|
||||
@@ -122,7 +122,11 @@
|
||||
"Filter": "过滤",
|
||||
"FirstMatchValue": "第一个匹配值",
|
||||
"ConfigLabel": "流程配置",
|
||||
"ConfigDescription": "定义流程以自动化工作流和业务流程。"
|
||||
"ConfigDescription": "定义流程以自动化工作流和业务流程。",
|
||||
"RunProcessPermission": "运行过程",
|
||||
"CancelProcessPermission": "取消过程",
|
||||
"ForbidRunProcessPermission": "禁止运行过程",
|
||||
"ForbidCancelProcessPermission": "禁止取消过程"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "找不到方法:{methodId}",
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Card } from '@hcengineering/card'
|
||||
import core, { Doc, FindOptions, SortingOrder } from '@hcengineering/core'
|
||||
import core, { Doc, FindOptions, Ref, SortingOrder, TypedSpace } from '@hcengineering/core'
|
||||
import { createQuery } from '@hcengineering/presentation'
|
||||
import { Execution } from '@hcengineering/process'
|
||||
import {
|
||||
@@ -38,6 +38,8 @@
|
||||
import process from '../plugin'
|
||||
import RunProcessPopup from './RunProcessPopup.svelte'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { checkMyPermission, permissionsStore } from '@hcengineering/contact-resources'
|
||||
import { PermissionsStore } from '@hcengineering/contact'
|
||||
|
||||
export let card: Card
|
||||
|
||||
@@ -108,13 +110,19 @@
|
||||
let viewOptions: ViewOptions | undefined
|
||||
|
||||
let docsProvided = false
|
||||
|
||||
function checkForbiddenPermission (permissionsStore: PermissionsStore): boolean {
|
||||
return checkMyPermission(process.permission.ForbidRunProcess, card.space as Ref<TypedSpace>, permissionsStore)
|
||||
}
|
||||
</script>
|
||||
|
||||
<Section icon={process.icon.Process} label={process.string.Processes} spaceBeforeContent>
|
||||
<svelte:fragment slot="header">
|
||||
<div class="buttons-group xsmall-gap">
|
||||
<ViewletsSettingButton bind:viewOptions viewletQuery={{ _id: viewletId }} kind={'tertiary'} bind:viewlet />
|
||||
<Button id={process.string.RunProcess} icon={IconAdd} kind={'ghost'} on:click={add} />
|
||||
{#if !checkForbiddenPermission($permissionsStore)}
|
||||
<Button id={process.string.RunProcess} icon={IconAdd} kind={'ghost'} on:click={add} />
|
||||
{/if}
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
}
|
||||
|
||||
const ancestors = client.getHierarchy().getAncestors(masterTag)
|
||||
const roles = client.getModel().findAllSync(card.class.Role, { attachedTo: { $in: ancestors } })
|
||||
const roles = client.getModel().findAllSync(card.class.Role, { type: { $in: ancestors } })
|
||||
</script>
|
||||
|
||||
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
|
||||
|
||||
@@ -11,12 +11,13 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { type Ref } from '@hcengineering/core'
|
||||
import { type Permission, type Ref } from '@hcengineering/core'
|
||||
import { mergeIds, type IntlString, type Resource } from '@hcengineering/platform'
|
||||
import { type PresentationMiddlewareCreator } from '@hcengineering/presentation'
|
||||
import process, { processId } from '@hcengineering/process'
|
||||
import { type AnyComponent } from '@hcengineering/ui'
|
||||
import { type ViewQueryAction, type Viewlet } from '@hcengineering/view'
|
||||
|
||||
export default mergeIds(processId, process, {
|
||||
viewlet: {
|
||||
ExecutionsList: '' as Ref<Viewlet>,
|
||||
@@ -208,6 +209,16 @@ export default mergeIds(processId, process, {
|
||||
Context: '' as IntlString,
|
||||
EmptyArray: '' as IntlString,
|
||||
ExecutionInitiator: '' as IntlString,
|
||||
ExecutionStarted: '' as IntlString
|
||||
ExecutionStarted: '' as IntlString,
|
||||
RunProcessPermission: '' as IntlString,
|
||||
CancelProcessPermission: '' as IntlString,
|
||||
ForbidRunProcessPermission: '' as IntlString,
|
||||
ForbidCancelProcessPermission: '' as IntlString
|
||||
},
|
||||
permission: {
|
||||
RunProcess: '' as Ref<Permission>,
|
||||
CancelProcess: '' as Ref<Permission>,
|
||||
ForbidRunProcess: '' as Ref<Permission>,
|
||||
ForbidCancelProcess: '' as Ref<Permission>
|
||||
}
|
||||
})
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
"Private": "Soukromé",
|
||||
"Public": "Veřejné",
|
||||
"Members": "Členové",
|
||||
"RoleLabel": "Role: {role}",
|
||||
"UpdateProductPermission": "Aktualizovat produkt",
|
||||
"UpdateProductDescription": "Umožňuje uživatelům aktualizovat produkt",
|
||||
"ChangeControl": "Změnit kontrolu",
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
"Private": "Privat",
|
||||
"Public": "Öffentlich",
|
||||
"Members": "Mitglieder",
|
||||
"RoleLabel": "Rolle: {role}",
|
||||
"UpdateProductPermission": "Produkt aktualisieren",
|
||||
"UpdateProductDescription": "Gewährt Benutzern die Möglichkeit, ein Produkt zu aktualisieren",
|
||||
"ChangeControl": "Änderungskontrolle",
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
"Private": "Private",
|
||||
"Public": "Public",
|
||||
"Members": "Members",
|
||||
"RoleLabel": "Role: {role}",
|
||||
"UpdateProductPermission": "Update product",
|
||||
"UpdateProductDescription": "Grants users ability to update a product",
|
||||
"ChangeControl": "Change control",
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
"Private": "Privé",
|
||||
"Public": "Public",
|
||||
"Members": "Membres",
|
||||
"RoleLabel": "Rôle : {role}",
|
||||
"UpdateProductPermission": "Mettre à jour le produit",
|
||||
"UpdateProductDescription": "Accorde aux utilisateurs la capacité de mettre à jour un produit",
|
||||
"ChangeControl": "Contrôle des modifications",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user