Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
Denis Bykhov
2025-11-10 14:41:05 +07:00
committed by GitHub
parent c6deabe416
commit d06b92ebdd
159 changed files with 2964 additions and 2229 deletions
+3 -2
View File
@@ -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",
+1892 -1885
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1 +1 @@
"0.7.292"
"0.7.301"
+1
View File
@@ -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
View File
@@ -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
+42 -2
View File
@@ -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
+153
View File
@@ -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
)
}
+26 -4
View File
@@ -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>
+7
View File
@@ -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'
+77
View File
@@ -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
)
}
+6 -6
View File
@@ -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>
+11 -1
View File
@@ -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ů"
}
}
+11 -1
View File
@@ -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"
}
}
+11 -1
View File
@@ -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"
}
}
+11 -1
View File
@@ -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"
}
}
+11 -1
View File
@@ -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"
}
}
+11 -1
View File
@@ -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"
}
}
+11 -1
View File
@@ -49,6 +49,16 @@
"CardContent": "何を共有しますか?",
"Feed": "フィード",
"AllCards": "すべてのカード",
"Favorites": "お気に入り"
"Favorites": "お気に入り",
"RemoveCard": "カードを削除",
"UpdateCard": "カードを更新",
"CreateCardPermission": "カードを作成",
"AddTagPermission": "タグを追加",
"RemoveTag": "タグを削除",
"ForbidRemoveCard": "カード削除を禁止",
"ForbidUpdateCard": "カード更新を禁止",
"ForbidCreateCardPermission": "カード作成を禁止",
"ForbidAddTagPermission": "タグ追加を禁止",
"ForbidRemoveTag": "タグ削除を禁止"
}
}
+11 -1
View File
@@ -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"
}
}
+11 -1
View File
@@ -49,6 +49,16 @@
"CardContent": "Чем вы хотите поделиться?",
"Feed": "Лента",
"AllCards": "Все карты",
"Favorites": "Избранное"
"Favorites": "Избранное",
"RemoveCard": "Удалить карточку",
"UpdateCard": "Обновить карточку",
"CreateCardPermission": "Создать карточку",
"AddTagPermission": "Добавить тег",
"RemoveTag": "Удалить тег",
"ForbidRemoveCard": "Запретить удаление карточки",
"ForbidUpdateCard": "Запретить обновление карточки",
"ForbidCreateCardPermission": "Запретить создание карточки",
"ForbidAddTagPermission": "Запретить добавление тега",
"ForbidRemoveTag": "Запретить удаление тега"
}
}
+11 -1
View File
@@ -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"
}
}
+11 -1
View File
@@ -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">
+13 -1
View File
@@ -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,
+17 -8
View File
@@ -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": "审查文档",
@@ -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,
-1
View File
@@ -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"
}
-1
View File
@@ -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"
}
-1
View File
@@ -58,7 +58,6 @@
"Icon": "Icon",
"Color": "Color",
"RoleLabel": "Role: {role}",
"ForbidCreateTeamspacePermission": "Forbid create teamspace",
"ForbidCreateTeamspacePermissionDescription": "Forbid users creating new teamspaces"
}
-1
View File
@@ -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"
}
-1
View File
@@ -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"
}
-1
View File
@@ -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"
}
-1
View File
@@ -51,7 +51,6 @@
"ConfigDescription": "共同ドキュメント編集のための拡張機能",
"Icon": "アイコン",
"Color": "色",
"RoleLabel": "ロール: {role}",
"ForbidCreateTeamspacePermission": "チームスペースの作成禁止",
"ForbidCreateTeamspacePermissionDescription": "ユーザーが新しいチームスペースを作成することを禁止します"
}
-1
View File
@@ -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"
}
-1
View File
@@ -58,7 +58,6 @@
"Icon": "Иконка",
"Color": "Цвет",
"RoleLabel": "Роль: {role}",
"ForbidCreateTeamspacePermission": "Запретить создание пространства",
"ForbidCreateTeamspacePermissionDescription": "Запрещает пользователям создавать новые пространства"
}
+1 -2
View File
@@ -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"
}
}
-1
View File
@@ -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] ?? []}
+1 -3
View File
@@ -87,8 +87,6 @@ export default mergeIds(documentId, document, {
CompareTo: '' as IntlString,
Color: '' as IntlString,
Icon: '' as IntlString,
RoleLabel: '' as IntlString
Icon: '' as IntlString
}
})
-1
View File
@@ -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"
-1
View File
@@ -26,7 +26,6 @@
"EditDrive": "Laufwerk bearbeiten",
"Rename": "Umbenennen",
"Restore": "Wiederherstellen",
"RoleLabel": "Rolle",
"Root": "/",
"ForbidCreateDrivePermission": "Laufwerkserstellung verbieten",
"ForbidCreateDrivePermissionDescription": "Verbietet Benutzern die Erstellung neuer Laufwerke"
-1
View File
@@ -26,7 +26,6 @@
"EditDrive": "Edit Drive",
"Rename": "Rename",
"Restore": "Restore",
"RoleLabel": "Role",
"Root": "/",
"ForbidCreateDrivePermission": "Forbid create drive",
"ForbidCreateDrivePermissionDescription": "Forbid users creating new drives"
-1
View File
@@ -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"
-1
View File
@@ -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"
-1
View File
@@ -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"
-1
View File
@@ -26,7 +26,6 @@
"EditDrive": "ドライブを編集",
"Rename": "名前を変更",
"Restore": "復元",
"RoleLabel": "ロール",
"Root": "/",
"ForbidCreateDrivePermission": "ドライブの作成禁止",
"ForbidCreateDrivePermissionDescription": "ユーザーが新しいドライブを作成することを禁止します"
-1
View File
@@ -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"
-1
View File
@@ -26,7 +26,6 @@
"EditDrive": "Редактировать",
"Rename": "Переименовать",
"Restore": "Восстановить",
"RoleLabel": "Роль",
"Root": "/",
"ForbidCreateDrivePermission": "Запретить создание диска",
"ForbidCreateDrivePermissionDescription": "Запрещает пользователям создавать новые диски"
-1
View File
@@ -26,7 +26,6 @@
"EditDrive": "Sürücüyü Düzenle",
"Rename": "Yeniden adlandır",
"Restore": "Geri yükle",
"RoleLabel": "Rol",
"Root": "/"
}
}
-1
View File
@@ -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] ?? []}
-1
View File
@@ -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
}
-1
View File
@@ -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"
}
-1
View File
@@ -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"
}
-1
View File
@@ -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"
}
-1
View File
@@ -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"
}
-1
View File
@@ -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"
}
-1
View File
@@ -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"
}
-1
View File
@@ -34,7 +34,6 @@
"ConfigDescription": "顧客関係管理のための拡張機能",
"EditFunnel": "ファネルを編集",
"FunnelMembers": "メンバー",
"RoleLabel": "ロール: {role}",
"ForbidCreateFunnelPermission": "ファネルの作成禁止",
"ForbidCreateFunnelPermissionDescription": "ユーザーが新しいファネルを作成することを禁止します"
}
-1
View File
@@ -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"
}
-1
View File
@@ -34,7 +34,6 @@
"ConfigDescription": "Расширение по работе с клиентами",
"EditFunnel": "Редактировать воронку",
"FunnelMembers": "Участники",
"RoleLabel": "Роль: {role}",
"ForbidCreateFunnelPermission": "Запретить создание воронки",
"ForbidCreateFunnelPermissionDescription": "Запрещает пользователям создавать новые воронки"
}
+1 -2
View File
@@ -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"
}
}
-1
View File
@@ -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] ?? []}
-1
View File
@@ -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: {
+5 -1
View File
@@ -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}",
+5 -1
View File
@@ -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}",
+5 -1
View File
@@ -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}",
+5 -1
View File
@@ -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}",
+5 -1
View File
@@ -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}",
+6 -2
View File
@@ -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}",
+5 -1
View File
@@ -121,7 +121,11 @@
"Filter": "フィルター",
"FirstMatchValue": "最初の一致する値",
"ConfigLabel": "プロセス構成",
"ConfigDescription": "ワークフローやビジネスプロセスを自動化するためのプロセスを定義します。"
"ConfigDescription": "ワークフローやビジネスプロセスを自動化するためのプロセスを定義します。",
"RunProcessPermission": "プロセスを実行",
"CancelProcessPermission": "プロセスをキャンセル",
"ForbidRunProcessPermission": "プロセスの実行を禁止",
"ForbidCancelProcessPermission": "プロセスのキャンセルを禁止"
},
"error": {
"MethodNotFound": "メソッドが見つかりません: {methodId}",
+5 -1
View File
@@ -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}",
+5 -1
View File
@@ -122,7 +122,11 @@
"Filter": "Фильтр",
"FirstMatchValue": "Первое подходящее значение",
"ConfigLabel": "Конфигурация процессов",
"ConfigDescription": "Определяйте процессы для автоматизации рабочих процессов и бизнес-процессов."
"ConfigDescription": "Определяйте процессы для автоматизации рабочих процессов и бизнес-процессов.",
"RunProcessPermission": "Запустить процесс",
"CancelProcessPermission": "Отменить процесс",
"ForbidRunProcessPermission": "Запретить запуск процесса",
"ForbidCancelProcessPermission": "Запретить отмену процесса"
},
"error": {
"MethodNotFound": "Метод не найден: {methodId}",
+5 -1
View File
@@ -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}",
+5 -1
View File
@@ -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')}>
+13 -2
View File
@@ -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>
}
})
-1
View File
@@ -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",
-1
View File
@@ -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",
-1
View File
@@ -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",
-1
View File
@@ -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