mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-28 04:25:03 +02:00
Ability to show ids in title (#10318)
Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
@@ -344,6 +344,7 @@ export interface TypeDate extends Type<Date> {
|
||||
*/
|
||||
export interface TypeIdentifier extends Type<string> {
|
||||
of: Ref<CustomSequence>
|
||||
showInPresenter?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -472,8 +472,8 @@ export function TypeRef (_class: Ref<Class<Doc>>): RefTo<Doc> {
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function TypeIdentifier (of: Ref<CustomSequence>): TypeIdentifierType {
|
||||
return { _class: core.class.TypeIdentifier, label: core.string.Id, icon: core.icon.TypeRef, of }
|
||||
export function TypeIdentifier (of: Ref<CustomSequence>, showInPresenter: boolean): TypeIdentifierType {
|
||||
return { _class: core.class.TypeIdentifier, label: core.string.Id, icon: core.icon.TypeRef, of, showInPresenter }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
export let withIcon: boolean = false
|
||||
export let withSelectIcon: boolean = true
|
||||
export let disableFocusOnMouseover: boolean = false
|
||||
export let withSearch: boolean = false
|
||||
export let withSearch: boolean = true
|
||||
|
||||
let container: HTMLElement
|
||||
let opened: boolean = false
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
})
|
||||
|
||||
function canChange (attr: AnyAttribute, permissionsStore: PermissionsStore): boolean {
|
||||
return canChangeAttribute(attr, object.space as Ref<TypedSpace>, permissionsStore)
|
||||
return canChangeAttribute(attr, object.space as Ref<TypedSpace>, permissionsStore, _class)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Card, MasterTag } from '@hcengineering/card'
|
||||
import { Ref } from '@hcengineering/core'
|
||||
import core, { Ref, TypeIdentifier } from '@hcengineering/core'
|
||||
import { Asset, getEmbeddedLabel } from '@hcengineering/platform'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { AnySvelteComponent, tooltip } from '@hcengineering/ui'
|
||||
@@ -56,6 +56,25 @@
|
||||
|
||||
$: _class = cardObj && (client.getHierarchy().getClass(cardObj?._class) as MasterTag)
|
||||
$: icon = _class && _class.icon
|
||||
|
||||
$: ids = getIds(cardObj)
|
||||
|
||||
function getIds (val: Card | undefined): string {
|
||||
if (val === undefined) return ''
|
||||
const h = client.getHierarchy()
|
||||
const attrs = h.getAllAttributes(val._class, core.class.Doc)
|
||||
const res: string[] = []
|
||||
for (const [k, v] of attrs) {
|
||||
if (v.type._class === core.class.TypeIdentifier) {
|
||||
const type = v.type as TypeIdentifier
|
||||
const str = (val as any)[k]
|
||||
if (type.showInPresenter === true && str !== undefined) {
|
||||
res.push(str)
|
||||
}
|
||||
}
|
||||
}
|
||||
return res.join(' ')
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if inline && cardObj}
|
||||
@@ -82,6 +101,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
<span class="overflow-label">
|
||||
{ids}
|
||||
{cardObj.title}
|
||||
<slot name="details" />
|
||||
</span>
|
||||
@@ -106,6 +126,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
<span class="overflow-label cropped-text-presenter">
|
||||
{ids}
|
||||
{cardObj.title}
|
||||
<slot name="details" />
|
||||
</span>
|
||||
@@ -113,6 +134,7 @@
|
||||
{/if}
|
||||
{:else}
|
||||
<span class="overflow-label" class:select-text={!noSelect} use:tooltip={{ label: getEmbeddedLabel(cardObj.title) }}>
|
||||
{ids}
|
||||
{cardObj.title}
|
||||
</span>
|
||||
{/if}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<script lang="ts">
|
||||
import { MasterTag } from '@hcengineering/card'
|
||||
import { Ref } from '@hcengineering/core'
|
||||
import { IconWithEmoji, createQuery } from '@hcengineering/presentation'
|
||||
import { IconWithEmoji, createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { clearSettingsStore } from '@hcengineering/setting-resources'
|
||||
import {
|
||||
Icon,
|
||||
@@ -40,10 +40,16 @@
|
||||
selectedTagId = loc.path[4] as Ref<MasterTag>
|
||||
}
|
||||
|
||||
const client = getClient()
|
||||
const h = client.getHierarchy()
|
||||
|
||||
let tags: MasterTag[] = []
|
||||
const tagsQuery = createQuery()
|
||||
$: tagsQuery.query(card.class.MasterTag, {}, (result) => {
|
||||
tags = result.filter((p) => p.removed !== true).sort((a, b) => a.label.localeCompare(b.label))
|
||||
tags = [
|
||||
h.getClass(card.class.Card),
|
||||
...result.filter((p) => p.removed !== true).sort((a, b) => a.label.localeCompare(b.label))
|
||||
]
|
||||
})
|
||||
|
||||
function selectProjectType (id: string): void {
|
||||
|
||||
@@ -92,7 +92,6 @@ export default mergeIds(cardId, card, {
|
||||
string: {
|
||||
CreateMasterTag: '' as IntlString,
|
||||
CreateTag: '' as IntlString,
|
||||
CreateCard: '' as IntlString,
|
||||
Content: '' as IntlString,
|
||||
Parent: '' as IntlString,
|
||||
CardLibrary: '' as IntlString,
|
||||
|
||||
@@ -191,7 +191,8 @@ const cardPlugin = plugin(cardId, {
|
||||
AddTag: '' as IntlString,
|
||||
Feed: '' as IntlString,
|
||||
AllCards: '' as IntlString,
|
||||
Favorites: '' as IntlString
|
||||
Favorites: '' as IntlString,
|
||||
CreateCard: '' as IntlString
|
||||
},
|
||||
section: {
|
||||
Attachments: '' as Ref<CardSection>,
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
</script>
|
||||
|
||||
<Modal
|
||||
label={getEmbeddedLabel('Create card from message')}
|
||||
label={cardPlugin.string.CreateCard}
|
||||
type="type-popup"
|
||||
okLabel={presentation.string.Create}
|
||||
okAction={attachCard}
|
||||
@@ -127,10 +127,10 @@
|
||||
|
||||
<div class="hulyModal-content__settingsSet">
|
||||
<div class="hulyModal-content__settingsSet-line">
|
||||
<span class="label"><Label label={getEmbeddedLabel('Card type')} /></span>
|
||||
<span class="label"><Label label={cardPlugin.string.MasterTag} /></span>
|
||||
<NestedDropdown
|
||||
items={classes}
|
||||
label={getEmbeddedLabel('Card type')}
|
||||
label={cardPlugin.string.MasterTag}
|
||||
on:selected={(e) => {
|
||||
selectedType = e.detail
|
||||
}}
|
||||
|
||||
@@ -209,6 +209,7 @@
|
||||
"DefaultStartWithRecording": "Povolit záznam v nových kancelářích",
|
||||
"ImportDocumentPermission": "Importovat dokumenty",
|
||||
"ImportDocumentDescription": "Umožňuje uživatelům importovat dokumenty do pracovního prostoru",
|
||||
"SelectUsers": "Vybrat uživatele"
|
||||
"SelectUsers": "Vybrat uživatele",
|
||||
"ShowInTitle": "Zobrazit v názvu"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,6 +211,7 @@
|
||||
"DefaultStartWithRecording": "Aufnahme in neuen Büroräumen aktivieren",
|
||||
"ImportDocumentPermission": "Dokumente importieren",
|
||||
"ImportDocumentDescription": "Gewährt Benutzern die Möglichkeit, Dokumente in den Arbeitsbereich zu importieren",
|
||||
"SelectUsers": "Benutzer auswählen"
|
||||
"SelectUsers": "Benutzer auswählen",
|
||||
"ShowInTitle": "Im Titel anzeigen"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,6 +211,7 @@
|
||||
"DefaultStartWithRecording": "Enable recording in new office rooms",
|
||||
"ImportDocumentPermission": "Import documents",
|
||||
"ImportDocumentDescription": "Grants users ability to import documents into the workspace",
|
||||
"SelectUsers": "Select users"
|
||||
"SelectUsers": "Select users",
|
||||
"ShowInTitle": "Show in title"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,6 +202,7 @@
|
||||
"DefaultStartWithRecording": "Habilitar grabación en nuevas oficinas",
|
||||
"ImportDocumentPermission": "Importar documentos",
|
||||
"ImportDocumentDescription": "Otorga a los usuarios la capacidad de importar documentos al espacio de trabajo",
|
||||
"SelectUsers": "Seleccionar usuarios"
|
||||
"SelectUsers": "Seleccionar usuarios",
|
||||
"ShowInTitle": "Mostrar en el título"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,6 +211,7 @@
|
||||
"DefaultStartWithRecording": "Activer l'enregistrement dans les nouveaux bureaux",
|
||||
"ImportDocumentPermission": "Importer des documents",
|
||||
"ImportDocumentDescription": "Accorde aux utilisateurs la possibilité d'importer des documents dans l'espace de travail",
|
||||
"SelectUsers": "Sélectionner des utilisateurs"
|
||||
"SelectUsers": "Sélectionner des utilisateurs",
|
||||
"ShowInTitle": "Afficher dans le titre"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,6 +211,7 @@
|
||||
"DefaultStartWithRecording": "Abilita registrazione nelle nuove stanze dell'ufficio",
|
||||
"ImportDocumentPermission": "Importa documenti",
|
||||
"ImportDocumentDescription": "Concede agli utenti la possibilità di importare documenti nell'area di lavoro",
|
||||
"SelectUsers": "Seleziona utenti"
|
||||
"SelectUsers": "Seleziona utenti",
|
||||
"ShowInTitle": "Mostra nel titolo"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,6 +211,7 @@
|
||||
"DefaultStartWithRecording": "新しいオフィスルームで録画を有効にする",
|
||||
"ImportDocumentPermission": "ドキュメントをインポート",
|
||||
"ImportDocumentDescription": "ユーザーにワークスペースにドキュメントをインポートする機能を付与します",
|
||||
"SelectUsers": "ユーザーを選択"
|
||||
"SelectUsers": "ユーザーを選択",
|
||||
"ShowInTitle": "タイトルに表示"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,6 +202,7 @@
|
||||
"DefaultStartWithRecording": "Habilitar gravação em novos escritórios",
|
||||
"ImportDocumentPermission": "Importar documentos",
|
||||
"ImportDocumentDescription": "Concede aos usuários a capacidade de importar documentos para o espaço de trabalho",
|
||||
"SelectUsers": "Selecionar usuários"
|
||||
"SelectUsers": "Selecionar usuários",
|
||||
"ShowInTitle": "Mostrar no título"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,6 +211,7 @@
|
||||
"DefaultStartWithRecording": "Включить запись в новых комнатах",
|
||||
"ImportDocumentPermission": "Импорт документов",
|
||||
"ImportDocumentDescription": "Предоставляет пользователям возможность импортировать документы в рабочее пространство",
|
||||
"SelectUsers": "Выбрать пользователей"
|
||||
"SelectUsers": "Выбрать пользователей",
|
||||
"ShowInTitle": "Показывать в заголовке"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,6 +211,7 @@
|
||||
"DefaultStartWithRecording": "Yeni ofis odalarında kaydı etkinleştir",
|
||||
"ImportDocumentPermission": "Belgeleri içe aktar",
|
||||
"ImportDocumentDescription": "Kullanıcılara çalışma alanına belge içe aktarma yeteneği verir",
|
||||
"SelectUsers": "Kullanıcıları seç"
|
||||
"SelectUsers": "Kullanıcıları seç",
|
||||
"ShowInTitle": "Başlıkta göster"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,6 +211,7 @@
|
||||
"DefaultStartWithRecording": "在新办公室启用录制",
|
||||
"ImportDocumentPermission": "导入文档",
|
||||
"ImportDocumentDescription": "授予用户将文档导入工作区的权限",
|
||||
"SelectUsers": "选择用户"
|
||||
"SelectUsers": "选择用户",
|
||||
"ShowInTitle": "在标题中显示"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,6 +162,7 @@
|
||||
{:else}
|
||||
<NestedDropdown
|
||||
items={classes}
|
||||
withSearch
|
||||
on:selected={(e) => {
|
||||
classARef = e.detail
|
||||
}}
|
||||
@@ -192,6 +193,7 @@
|
||||
<div>
|
||||
<NestedDropdown
|
||||
items={classes}
|
||||
withSearch
|
||||
on:selected={(e) => {
|
||||
classBRef = e.detail
|
||||
}}
|
||||
|
||||
@@ -134,6 +134,12 @@
|
||||
defaultValue = e.detail?.defaultValue
|
||||
}
|
||||
|
||||
const onTypePatch = async (type: Type<any>) => {
|
||||
if (type !== undefined && type._class === attribute.type._class) {
|
||||
await client.updateDoc(attribute._class, attribute.space, attribute._id, { type })
|
||||
}
|
||||
}
|
||||
|
||||
async function remove (evt: MouseEvent): Promise<void> {
|
||||
const impl = await getResource(view.actionImpl.Delete)
|
||||
await impl(attribute, evt, {
|
||||
@@ -165,7 +171,7 @@
|
||||
return `${attr._id}_${forbidden ? 'forbidden' : 'allowed'}` as Ref<AttributePermission>
|
||||
}
|
||||
|
||||
function changeRestricted (e: CustomEvent<boolean>): void {
|
||||
function changeRestricted (): void {
|
||||
showPopup(
|
||||
MessageBox,
|
||||
{
|
||||
@@ -285,7 +291,8 @@
|
||||
width: '100%',
|
||||
editable: !exist && !disabled,
|
||||
kind: 'regular',
|
||||
size: 'large'
|
||||
size: 'large',
|
||||
onTypePatch
|
||||
}}
|
||||
{disabled}
|
||||
on:change={handleChange}
|
||||
|
||||
@@ -13,15 +13,16 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import core, { CustomSequence, Ref, TypeIdentifier as TypeId } from '@hcengineering/core'
|
||||
import core, { CustomSequence, Ref, Type, TypeIdentifier as TypeId } from '@hcengineering/core'
|
||||
import { TypeIdentifier } from '@hcengineering/model'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { EditBox, Label } from '@hcengineering/ui'
|
||||
import { EditBox, Label, Toggle } from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import setting from '../../plugin'
|
||||
|
||||
export let type: TypeId | undefined
|
||||
export let editable: boolean = true
|
||||
export let onTypePatch: ((type: Type<any>) => Promise<void>) | undefined = undefined
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const client = getClient()
|
||||
@@ -30,6 +31,7 @@
|
||||
|
||||
let identifier: string = ''
|
||||
let sequences: CustomSequence[] = []
|
||||
let showInPresenter = type?.showInPresenter ?? false
|
||||
|
||||
$: identifiers = new Set(sequences.filter((p) => p._id !== seq).map((s) => s.prefix.toUpperCase()))
|
||||
|
||||
@@ -54,7 +56,16 @@
|
||||
attachedTo: core.class.CustomSequence
|
||||
})
|
||||
seq = newSeq
|
||||
dispatch('change', { type: TypeIdentifier(newSeq) })
|
||||
dispatch('change', { type: TypeIdentifier(newSeq, showInPresenter) })
|
||||
}
|
||||
}
|
||||
|
||||
async function changeShowing () {
|
||||
if (seq === undefined) return
|
||||
const type = TypeIdentifier(seq, showInPresenter)
|
||||
dispatch('change', { type })
|
||||
if (!editable) {
|
||||
onTypePatch?.(type)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -77,6 +88,10 @@
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<span class="label">
|
||||
<Label label={setting.string.ShowInTitle} />
|
||||
</span>
|
||||
<Toggle bind:on={showInPresenter} on:change={changeShowing} />
|
||||
|
||||
<style lang="scss">
|
||||
.duplicated-identifier {
|
||||
|
||||
@@ -41,12 +41,7 @@
|
||||
|
||||
function fillClasses (classes: Ref<Class<Doc>>[], exclude: Ref<Class<Doc>>[]): DropdownIntlItem[] {
|
||||
const res: DropdownIntlItem[] = []
|
||||
const descendants = new Set(
|
||||
classes
|
||||
.map((p) => hierarchy.getDescendants(p))
|
||||
.reduce((a, b) => a.concat(b))
|
||||
.filter((p) => p !== card.class.Card)
|
||||
)
|
||||
const descendants = new Set(classes.map((p) => hierarchy.getDescendants(p)).reduce((a, b) => a.concat(b)))
|
||||
// exclude removed card types
|
||||
const removedTypes = client.getModel().findAllSync(card.class.MasterTag, { removed: true })
|
||||
const excluded = new Set(removedTypes.map((p) => p._id))
|
||||
|
||||
@@ -155,6 +155,7 @@ export default mergeIds(settingId, setting, {
|
||||
Restricted: '' as IntlString,
|
||||
RestrictedAttributeWarning: '' as IntlString,
|
||||
PasswordAgingRule: '' as IntlString,
|
||||
PasswordAgingRuleDescription: '' as IntlString
|
||||
PasswordAgingRuleDescription: '' as IntlString,
|
||||
ShowInTitle: '' as IntlString
|
||||
}
|
||||
})
|
||||
|
||||
@@ -168,7 +168,7 @@
|
||||
): boolean {
|
||||
if (attr === undefined) return true
|
||||
if (permissionsStore === undefined) return true
|
||||
return canChangeAttribute(attr, object.space as Ref<TypedSpace>, permissionsStore)
|
||||
return canChangeAttribute(attr, object.space as Ref<TypedSpace>, permissionsStore, object._class)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -356,7 +356,7 @@
|
||||
): boolean {
|
||||
if (permissionsStore === undefined) return true
|
||||
if (attr === undefined) return true
|
||||
return canChangeAttribute(attr, object.space as Ref<TypedSpace>, permissionsStore)
|
||||
return canChangeAttribute(attr, object.space as Ref<TypedSpace>, permissionsStore, object._class)
|
||||
}
|
||||
|
||||
async function canEdit (object: Doc): Promise<boolean> {
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
): boolean {
|
||||
if (attr === undefined) return true
|
||||
if (permissionsStore === undefined) return true
|
||||
return canChangeAttribute(attr, object.space as Ref<TypedSpace>, permissionsStore)
|
||||
return canChangeAttribute(attr, object.space as Ref<TypedSpace>, permissionsStore, object._class)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ export function canChangeAttribute (
|
||||
attr: AnyAttribute,
|
||||
space: Ref<TypedSpace>,
|
||||
store: PermissionsStore,
|
||||
_class?: Ref<Class<Doc>>
|
||||
_class: Ref<Class<Doc>>
|
||||
): boolean {
|
||||
const arePermissionsDisabled = getMetadata(core.metadata.DisablePermissions) ?? false
|
||||
if (arePermissionsDisabled) return true
|
||||
@@ -43,7 +43,7 @@ export function canChangeAttribute (
|
||||
return true
|
||||
}
|
||||
|
||||
return canChangeDoc(_class ?? attr.attributeOf, space, store)
|
||||
return canChangeDoc(_class, space, store)
|
||||
}
|
||||
|
||||
export function canChangeDoc (_class: Ref<Class<Doc>>, space: Ref<Space>, store: PermissionsStore): boolean {
|
||||
@@ -51,6 +51,16 @@ export function canChangeDoc (_class: Ref<Class<Doc>>, space: Ref<Space>, store:
|
||||
if (arePermissionsDisabled) return true
|
||||
if (store.whitelist.has(space)) return true
|
||||
if (store.ps[space] !== undefined) {
|
||||
const forbiddenClId = `${_class}_forbidden` as Ref<Permission>
|
||||
const forbiddenCl = store.ps[space]?.has(forbiddenClId)
|
||||
if (forbiddenCl) {
|
||||
return false
|
||||
}
|
||||
const allowedClId = `${_class}_allowed` as Ref<Permission>
|
||||
const allowedCl = store.ps[space]?.has(allowedClId)
|
||||
if (allowedCl) {
|
||||
return true
|
||||
}
|
||||
const client = getClient()
|
||||
const h = client.getHierarchy()
|
||||
const ancestors = h.getAncestors(_class)
|
||||
|
||||
@@ -157,7 +157,6 @@ export class CustomAttributesPage {
|
||||
await expect(this.lead().nth(1)).toBeVisible()
|
||||
await expect(this.issue().nth(0)).toBeVisible()
|
||||
await expect(this.issue().nth(1)).toBeVisible()
|
||||
await expect(this.card()).toBeVisible()
|
||||
await expect(this.product()).toBeVisible()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,6 @@ export class ClassesPage {
|
||||
await expect(this.lead().nth(1)).toBeVisible()
|
||||
await expect(this.issue().nth(0)).toBeVisible()
|
||||
await expect(this.issue().nth(1)).toBeVisible()
|
||||
await expect(this.card()).toBeVisible()
|
||||
await expect(this.product()).toBeVisible()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user