Markup properties (#10804)

Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
Denis Bykhov
2026-04-27 13:46:08 +05:00
committed by GitHub
parent 338b16d665
commit d2591a1e71
50 changed files with 322 additions and 42 deletions
+2 -2
View File
@@ -97,8 +97,8 @@ jobs:
node common/scripts/install-run-rush.js install
fi
- name: Checking model version is updated...
run: node common/scripts/check_model_version.js
# - name: Checking model version is updated...
# run: node common/scripts/check_model_version.js
- name: Checking for mis-matching dependencies...
run: node common/scripts/install-run-rush.js check
+4 -1
View File
@@ -34283,6 +34283,9 @@ importers:
'@hcengineering/server-process':
specifier: workspace:^0.7.0
version: link:../process
'@hcengineering/text-core':
specifier: workspace:^0.7.19
version: link:../../foundations/core/packages/text-core
'@hcengineering/time':
specifier: workspace:^0.7.0
version: link:../../plugins/time
@@ -61584,7 +61587,7 @@ snapshots:
node-loader@2.0.0(webpack@5.102.1):
dependencies:
loader-utils: 2.0.4
webpack: 5.102.1(esbuild@0.25.12)(webpack-cli@5.1.4)
webpack: 5.102.1
node-localstorage@2.2.1:
dependencies:
@@ -54,7 +54,8 @@ export enum MarkupMarkType {
strike = 'strike',
underline = 'underline',
textColor = 'textColor',
textStyle = 'textStyle'
textStyle = 'textStyle',
highlight = 'highlight'
}
/** @public */
+12
View File
@@ -1124,6 +1124,18 @@ function defineTabs (builder: Builder): void {
card.section.Properties
)
builder.createDoc(
card.class.CardSection,
core.space.Model,
{
label: card.string.RichtextProperties,
component: card.sectionComponent.MarkupPropertiesSection,
order: 150,
navigation: []
},
card.section.MarkupProperties
)
builder.createDoc(
card.class.CardSection,
core.space.Model,
+26
View File
@@ -626,6 +626,32 @@ export function defineFunctions (builder: Builder): void {
process.function.StringFromBoolean
)
builder.createDoc(
process.class.ProcessFunction,
core.space.Model,
{
of: core.class.TypeMarkup,
to: core.class.TypeString,
category: 'attribute',
label: process.string.TextFromMarkup,
type: 'convert'
},
process.function.StringFromMarkup
)
builder.createDoc(
process.class.ProcessFunction,
core.space.Model,
{
of: core.class.TypeString,
to: core.class.TypeMarkup,
category: 'attribute',
label: process.string.MarkupFromText,
type: 'convert'
},
process.function.MarkupFromString
)
builder.createDoc(
process.class.ProcessFunction,
core.space.Model,
+8
View File
@@ -179,10 +179,18 @@ export function createModel (builder: Builder): void {
func: serverProcess.transform.StringFromDate
})
builder.mixin(process.function.StringFromMarkup, process.class.ProcessFunction, serverProcess.mixin.FuncImpl, {
func: serverProcess.transform.StringFromMarkup
})
builder.mixin(process.function.StringFromBoolean, process.class.ProcessFunction, serverProcess.mixin.FuncImpl, {
func: serverProcess.transform.StringFromBoolean
})
builder.mixin(process.function.MarkupFromString, process.class.ProcessFunction, serverProcess.mixin.FuncImpl, {
func: serverProcess.transform.MarkupFromString
})
builder.mixin(process.function.NumberFromDate, process.class.ProcessFunction, serverProcess.mixin.FuncImpl, {
func: serverProcess.transform.NumberFromDate
})
+4
View File
@@ -530,6 +530,10 @@ export function createModel (builder: Builder): void {
editor: setting.component.EmployeeRefEditor
})
builder.mixin(core.class.TypeMarkup, core.class.Class, view.mixin.ObjectEditor, {
editor: setting.component.MarkupTypeEditor
})
builder.mixin(core.class.TypeNumber, core.class.Class, view.mixin.ObjectEditor, {
editor: setting.component.NumberTypeEditor
})
+1
View File
@@ -40,6 +40,7 @@ export default mergeIds(settingId, setting, {
IdentifierTypeEditor: '' as AnyComponent,
EmployeeRefEditor: '' as AnyComponent,
DateTypeEditor: '' as AnyComponent,
MarkupTypeEditor: '' as AnyComponent,
RefEditor: '' as AnyComponent,
AssociationEditor: '' as AnyComponent,
EnumTypeEditor: '' as AnyComponent,
@@ -14,13 +14,13 @@
// limitations under the License.
-->
<script lang="ts">
import { checkForbiddenPermission, type Class, type Doc, type Ref } from '@hcengineering/core'
import { 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 view from '@hcengineering/view'
import { createEventDispatcher } from 'svelte'
import { getAttribute, KeyedAttribute, updateAttribute } from '../attributes'
import { getAttributeEditor, getClient } from '../utils'
import view from '@hcengineering/view'
export let key: KeyedAttribute | string
export let object: Doc | Record<string, any>
@@ -69,6 +69,8 @@
<s><slot /></s>
{:else if mark.type === MarkupMarkType.underline}
<u><slot /></u>
{:else if mark.type === MarkupMarkType.highlight}
<mark><slot /></mark>
{:else}
unknown mark: "{mark.type}"
<slot />
+2 -1
View File
@@ -83,6 +83,7 @@
"LayoutAuto": "Auto",
"SingleColumn": "Jeden sloupec",
"TwoColumns": "Dva sloupce",
"Grid": "Mřížka"
"Grid": "Mřížka",
"RichtextProperties": "Textová pole"
}
}
+2 -1
View File
@@ -83,6 +83,7 @@
"LayoutAuto": "Auto",
"SingleColumn": "Einspaltig",
"TwoColumns": "Zwei spaltig",
"Grid": "Gitter"
"Grid": "Gitter",
"RichtextProperties": "Textfelder"
}
}
+2 -1
View File
@@ -83,6 +83,7 @@
"LayoutAuto": "Auto",
"SingleColumn": "Single column",
"TwoColumns": "Two columns",
"Grid": "Grid"
"Grid": "Grid",
"RichtextProperties": "Richtext Properties"
}
}
+2 -1
View File
@@ -83,6 +83,7 @@
"LayoutAuto": "Auto",
"SingleColumn": "Una columna",
"TwoColumns": "Dos columnas",
"Grid": "Cuadrícula"
"Grid": "Cuadrícula",
"RichtextProperties": "Campos de texto"
}
}
+2 -1
View File
@@ -83,6 +83,7 @@
"LayoutAuto": "Auto",
"SingleColumn": "Une colonne",
"TwoColumns": "Deux colonnes",
"Grid": "Grille"
"Grid": "Grille",
"RichtextProperties": "Champs de texte"
}
}
+2 -1
View File
@@ -83,6 +83,7 @@
"LayoutAuto": "Auto",
"SingleColumn": "Una colonna",
"TwoColumns": "Due colonne",
"Grid": "Griglia"
"Grid": "Griglia",
"RichtextProperties": "Campo di testo"
}
}
+2 -1
View File
@@ -83,6 +83,7 @@
"LayoutAuto": "自動",
"SingleColumn": "1列",
"TwoColumns": "2列",
"Grid": "グリッド"
"Grid": "グリッド",
"RichtextProperties": "リッチテキストフィールド"
}
}
+2 -1
View File
@@ -83,6 +83,7 @@
"LayoutAuto": "Automático",
"SingleColumn": "Uma coluna",
"TwoColumns": "Duas colunas",
"Grid": "Grade"
"Grid": "Grade",
"RichtextProperties": "Campos de texto"
}
}
+2 -1
View File
@@ -83,6 +83,7 @@
"LayoutAuto": "Automático",
"SingleColumn": "Uma coluna",
"TwoColumns": "Duas colunas",
"Grid": "Grade"
"Grid": "Grade",
"RichtextProperties": "Campo de texto"
}
}
+2 -1
View File
@@ -83,6 +83,7 @@
"LayoutAuto": "Авто",
"SingleColumn": "Один столбец",
"TwoColumns": "Два столбца",
"Grid": "Сетка"
"Grid": "Сетка",
"RichtextProperties": "Текстовые поля"
}
}
+2 -1
View File
@@ -83,6 +83,7 @@
"LayoutAuto": "Otomatik",
"SingleColumn": "Tek sütun",
"TwoColumns": "İki sütun",
"Grid": "Izgara"
"Grid": "Izgara",
"RichtextProperties": "Zengin metin alanları"
}
}
+2 -1
View File
@@ -83,6 +83,7 @@
"LayoutAuto": "自动",
"SingleColumn": "单列",
"TwoColumns": "两列",
"Grid": "网格"
"Grid": "网格",
"RichtextProperties": "富文本字段"
}
}
@@ -45,7 +45,10 @@
const filtredKeys = [...hierarchy.getAllAttributes(_class, to).entries()]
.filter(
([key, value]) =>
value.hidden !== true && !ignoreKeys.includes(key) && !isCollectionAttr(hierarchy, { key, attr: value })
value.hidden !== true &&
!ignoreKeys.includes(key) &&
!isCollectionAttr(hierarchy, { key, attr: value }) &&
value.type._class !== core.class.TypeMarkup
)
.map(([key, attr]) => ({ key, attr }))
@@ -0,0 +1,84 @@
<!--
// Copyright © 2026 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
-->
<script lang="ts">
import { Card, Tag } from '@hcengineering/card'
import core, { Class, Doc, Ref, toRank } from '@hcengineering/core'
import { getClient, KeyedAttribute, updateAttribute } from '@hcengineering/presentation'
import { Label } from '@hcengineering/ui'
import { MarkupEditor } from '@hcengineering/view-resources'
import { createEventDispatcher } from 'svelte'
export let doc: Card
export let tag: Tag | undefined
export let readonly: boolean = false
let keys: KeyedAttribute[] = []
const dispatch = createEventDispatcher()
const client = getClient()
const hierarchy = client.getHierarchy()
function updateKeys (_class: Ref<Class<Doc>>, to: Ref<Class<Doc>> | undefined): void {
console.log('tag', _class, to)
const filtredKeys = [...hierarchy.getAllAttributes(_class, to).entries()]
.filter(([key, value]) => value.hidden !== true && value.type._class === core.class.TypeMarkup)
.map(([key, attr]) => ({ key, attr }))
keys = filtredKeys.sort((a, b) => {
const rankA = a.attr.rank ?? toRank(a.attr._id) ?? ''
const rankB = b.attr.rank ?? toRank(b.attr._id) ?? ''
return rankA.localeCompare(rankB)
})
}
$: _class = tag?._id ?? doc._class
$: to = tag?.extends
$: updateKeys(_class, to)
function getValue (doc: Card, key: string): string {
const target = tag !== undefined ? hierarchy.as(doc, tag._id) : doc
return (target as any)[key]
}
function onChange (value: any, attr: KeyedAttribute): void {
dispatch('update', { key: attr, value })
void updateAttribute(client, doc, doc._class, attr, value, false, {
objectId: doc._id
})
}
</script>
{#each keys as key}
<div class="px-4 w-full">
<span>
<Label label={key.attr.label} />
{#if tag}
<span class="text-xs">
(<Label label={tag.label} />)
</span>
{/if}
</span>
<MarkupEditor
value={getValue(doc, key.key)}
onChange={(value) => {
onChange(value, key)
}}
{readonly}
/>
</div>
{/each}
@@ -0,0 +1,43 @@
<!--
// Copyright © 2025 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
-->
<script lang="ts">
import { Card } from '@hcengineering/card'
import { Doc, Mixin } from '@hcengineering/core'
import { getDocMixins } from '@hcengineering/view-resources'
import { createEventDispatcher, onMount } from 'svelte'
import MarkupProperties from '../MarkupProperties.svelte'
export let readonly: boolean = false
export let doc: Card
export let hidden: boolean = false
const dispatch = createEventDispatcher()
let mixins: Array<Mixin<Doc>> = []
$: mixins = getDocMixins(doc)
onMount(() => {
dispatch('loaded')
})
</script>
{#if !hidden}
<div class="w-full flex flex-col flex-gap-4">
<MarkupProperties {doc} {readonly} tag={undefined} on:update />
{#each mixins as mixin}
<MarkupProperties {doc} {readonly} tag={mixin} on:update />
{/each}
</div>
{/if}
+3 -1
View File
@@ -77,6 +77,7 @@ import PropertiesCardSection from './components/sections/PropertiesSection.svelt
import RelationsCardSection from './components/sections/RelationsSection.svelte'
import CardCommunicatiomMessages from './components/sections/CardCommunicatiomMessages.svelte'
import OldMessagesCardSection from './components/sections/OldMessagesCardSection.svelte'
import MarkupPropertiesCardSection from './components/sections/MarkupPropertiesSection.svelte'
import FavoriteCardPresenter from './components/FavoriteCardPresenter.svelte'
import CardTagsColored from './components/CardTagsColored.svelte'
@@ -149,7 +150,8 @@ export default async (): Promise<Resources> => ({
PropertiesSection: PropertiesCardSection,
RelationsSection: RelationsCardSection,
OldMessagesSection: OldMessagesCardSection,
CommunicationMessagesSection: CardCommunicatiomMessages
CommunicationMessagesSection: CardCommunicatiomMessages,
MarkupPropertiesSection: MarkupPropertiesCardSection
},
completion: {
CardQuery: queryCard
+2
View File
@@ -83,6 +83,7 @@ export default mergeIds(cardId, card, {
ChildrenSection: '' as AnyComponent,
ContentSection: '' as AnyComponent,
PropertiesSection: '' as AnyComponent,
MarkupPropertiesSection: '' as AnyComponent,
RelationsSection: '' as AnyComponent,
CommunicationMessagesSection: '' as AnyComponent,
OldMessagesSection: '' as AnyComponent
@@ -132,6 +133,7 @@ export default mergeIds(cardId, card, {
CreateSpace: '' as IntlString,
NumberTypes: '' as IntlString,
Properties: '' as IntlString,
RichtextProperties: '' as IntlString,
NoChildren: '' as IntlString,
AddCollaborators: '' as IntlString,
CardTitle: '' as IntlString,
+1
View File
@@ -221,6 +221,7 @@ const cardPlugin = plugin(cardId, {
Children: '' as Ref<CardSection>,
Content: '' as Ref<CardSection>,
Properties: '' as Ref<CardSection>,
MarkupProperties: '' as Ref<CardSection>,
Relations: '' as Ref<CardSection>,
OldMessages: '' as Ref<CardSection>,
CommunicationMessages: '' as Ref<CardSection>
+3 -1
View File
@@ -166,7 +166,9 @@
"DateDifference": "Rozdíl dat",
"EmptyValue": "Prázdná hodnota",
"Min": "Min",
"Max": "Max"
"Max": "Max",
"MarkupFromText": "MarkUp z textu",
"TextFromMarkup": "Text z MarkUp"
},
"error": {
"MethodNotFound": "Metoda nenalezena: {methodId}",
+3 -1
View File
@@ -166,7 +166,9 @@
"DateDifference": "Datumsdifferenz",
"EmptyValue": "Leerer Wert",
"Min": "Min",
"Max": "Max"
"Max": "Max",
"TextFromMarkup": "Text aus Markup",
"MarkupFromText": "Markup aus Text"
},
"error": {
"MethodNotFound": "Methode nicht gefunden: {methodId}",
+3 -1
View File
@@ -171,7 +171,9 @@
"MonthFromDate": "Month from date",
"DayFromDate": "Day from date",
"DateDifference": "Date difference",
"EmptyValue": "Empty value"
"EmptyValue": "Empty value",
"TextFromMarkup": "Text from markup",
"MarkupFromText": "Markup from text"
},
"error": {
"MethodNotFound": "Method not found: {methodId}",
+3 -1
View File
@@ -171,7 +171,9 @@
"MonthFromDate": "Mes desde fecha",
"DayFromDate": "Día desde fecha",
"DateDifference": "Diferencia de fechas",
"EmptyValue": "Valor vacío"
"EmptyValue": "Valor vacío",
"TextFromMarkup": "Texto desde markup",
"MarkupFromText": "Markup desde texto"
},
"error": {
"MethodNotFound": "Método no encontrado: {methodId}",
+3 -1
View File
@@ -171,7 +171,9 @@
"MonthFromDate": "Mois depuis date",
"DayFromDate": "Jour depuis date",
"DateDifference": "Différence de dates",
"EmptyValue": "Valeur vide"
"EmptyValue": "Valeur vide",
"TextFromMarkup": "Texte depuis markup",
"MarkupFromText": "Markup depuis texte"
},
"error": {
"MethodNotFound": "Méthode introuvable : {methodId}",
+3 -1
View File
@@ -171,7 +171,9 @@
"MonthFromDate": "Mese da data",
"DayFromDate": "Giorno da data",
"DateDifference": "Differenza di date",
"EmptyValue": "Valore vuoto"
"EmptyValue": "Valore vuoto",
"TextFromMarkup": "Testo da markup",
"MarkupFromText": "Markup da testo"
},
"error": {
"MethodNotFound": "Metodo non trovato: {methodId}",
+3 -1
View File
@@ -170,7 +170,9 @@
"MonthFromDate": "日付から月",
"DayFromDate": "日付から日",
"DateDifference": "日付の差",
"EmptyValue": "空の値"
"EmptyValue": "空の値",
"TextFromMarkup": "テキストからマークアップ",
"MarkupFromText": "マークアップからテキスト"
},
"error": {
"MethodNotFound": "メソッドが見つかりません: {methodId}",
+3 -1
View File
@@ -159,7 +159,9 @@
"MonthFromDate": "Mês de data",
"DayFromDate": "Dia de data",
"DateDifference": "Diferença de datas",
"EmptyValue": "Valor vazio"
"EmptyValue": "Valor vazio",
"TextFromMarkup": "Texto de marcação",
"MarkupFromText": "Marcação de texto"
},
"error": {
"MethodNotFound": "Método não encontrado: {methodId}",
+3 -1
View File
@@ -171,7 +171,9 @@
"MonthFromDate": "Mês de data",
"DayFromDate": "Dia de data",
"DateDifference": "Diferença de datas",
"EmptyValue": "Valor vazio"
"EmptyValue": "Valor vazio",
"TextFromMarkup": "Texto de marcação",
"MarkupFromText": "Marcação de texto"
},
"error": {
"MethodNotFound": "Método não encontrado: {methodId}",
+3 -1
View File
@@ -171,7 +171,9 @@
"MonthFromDate": "Месяц из даты",
"DayFromDate": "День из даты",
"DateDifference": "Разница дат",
"EmptyValue": "Пустое значение"
"EmptyValue": "Пустое значение",
"MarkupFromText": "Текст из разметки",
"TextFromMarkup": "Разметка из текста"
},
"error": {
"MethodNotFound": "Метод не найден: {methodId}",
+3 -1
View File
@@ -166,7 +166,9 @@
"MonthFromDate": "Tarihten ay",
"DayFromDate": "Tarihten gün",
"DateDifference": "Tarih farkı",
"EmptyValue": "Boş değer"
"EmptyValue": "Boş değer",
"TextFromMarkup": "Metinden işaretleme",
"MarkupFromText": "İşaretlemeden metin"
},
"error": {
"MethodNotFound": "Metod bulunamadı: {methodId}",
+3 -1
View File
@@ -171,7 +171,9 @@
"MonthFromDate": "日期到月份",
"DayFromDate": "日期到天",
"DateDifference": "日期差异",
"EmptyValue": "空值"
"EmptyValue": "空值",
"TextFromMarkup": "标记到文本",
"MarkupFromText": "文本到标记"
},
"error": {
"MethodNotFound": "找不到方法:{methodId}",
@@ -108,7 +108,7 @@
this={editor}
label={attribute?.label}
placeholder={attribute?.label}
kind={'ghost'}
kind={'link'}
size={'large'}
width={'100%'}
justify={'left'}
+2
View File
@@ -270,6 +270,8 @@ export default mergeIds(processId, process, {
TextFromNumber: '' as IntlString,
TextFromDate: '' as IntlString,
TextFromCheckbox: '' as IntlString,
TextFromMarkup: '' as IntlString,
MarkupFromText: '' as IntlString,
NumberFromDate: '' as IntlString,
DateFromNumber: '' as IntlString,
NumberFromText: '' as IntlString,
+2
View File
@@ -380,6 +380,8 @@ export default plugin(processId, {
CurrentDate: '' as Ref<ProcessFunction>,
StringFromNumber: '' as Ref<ProcessFunction>,
StringFromDate: '' as Ref<ProcessFunction>,
StringFromMarkup: '' as Ref<ProcessFunction>,
MarkupFromString: '' as Ref<ProcessFunction>,
StringFromBoolean: '' as Ref<ProcessFunction>,
NumberFromDate: '' as Ref<ProcessFunction>,
DateFromNumber: '' as Ref<ProcessFunction>,
@@ -0,0 +1,24 @@
<!--
// Copyright © 2026 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
-->
<script lang="ts">
import { TypeMarkup } from '@hcengineering/model'
import { createEventDispatcher, onMount } from 'svelte'
const dispatch = createEventDispatcher()
onMount(() => {
dispatch('change', { type: TypeMarkup() })
})
</script>
+2
View File
@@ -62,6 +62,7 @@ import RefEditor from './components/typeEditors/RefEditor.svelte'
import IdentifierTypeEditor from './components/typeEditors/IdentifierTypeEditor.svelte'
import RelationSetting from './components/RelationSetting.svelte'
import RoleAssignmentEditor from './components/typeEditors/RoleAssignmentEditor.svelte'
import MarkupTypeEditor from './components/typeEditors/MarkupTypeEditor.svelte'
import StringTypeEditor from './components/typeEditors/StringTypeEditor.svelte'
import WorkspaceSettings from './components/WorkspaceSettings.svelte'
import SettingsWidget from './components/SettingsWidget.svelte'
@@ -156,6 +157,7 @@ export default async (): Promise<Resources> => ({
ClassPermissionPresenter,
SpaceTypeDescriptorPresenter,
SpaceTypeGeneralSectionEditor,
MarkupTypeEditor,
SpaceTypePropertiesSectionEditor,
SpaceTypeRolesSectionEditor,
RoleEditor,
@@ -18,9 +18,11 @@
import { MessageViewer } from '@hcengineering/presentation'
import { Button, eventToHTMLElement, Label, showPopup } from '@hcengineering/ui'
import MarkupEditorPopup from './MarkupEditorPopup.svelte'
import { StyledTextBox } from '@hcengineering/text-editor-resources'
import textEditorPlugin from '@hcengineering/text-editor'
// export let label: IntlString
export let placeholder: IntlString
export let placeholder: IntlString = textEditorPlugin.string.EditorPlaceholder
export let value: string
// export let focus: boolean = false
export let onChange: (value: string) => void
@@ -62,10 +64,14 @@
</div>
</svelte:fragment>
</Button>
{:else if readonly}
{#if value}
<span class="overflow-label">{value}</span>
{:else}
<span class="content-dark-color"><Label label={placeholder} /></span>
{/if}
{:else}
<StyledTextBox
content={value}
{placeholder}
alwaysEdit
mode={2}
on:value={(e) => {
onChange(e.detail)
}}
/>
{/if}
@@ -42,6 +42,7 @@
"@hcengineering/contact": "workspace:^0.7.0",
"@hcengineering/card": "workspace:^0.7.0",
"@hcengineering/server-process": "workspace:^0.7.0",
"@hcengineering/text-core": "workspace:^0.7.19",
"@hcengineering/server-core": "workspace:^0.7.19",
"@hcengineering/platform": "workspace:^0.7.20",
"@hcengineering/process": "workspace:^0.7.0"
@@ -106,6 +106,7 @@ import {
Insert,
LastValue,
LowerCase,
MarkupFromString,
Max,
Min,
Modulo,
@@ -128,6 +129,7 @@ import {
Sqrt,
StringFromBoolean,
StringFromDate,
StringFromMarkup,
StringFromNumber,
Subtract,
Trim,
@@ -793,7 +795,9 @@ export default async () => ({
DayFromDate,
DateDifference,
Min,
Max
Max,
StringFromMarkup,
MarkupFromString
},
rollbacks: {
ToDoCloseRollback,
@@ -13,12 +13,13 @@
// limitations under the License.
//
import cardPlugin from '@hcengineering/card'
import contact, { Employee, Person } from '@hcengineering/contact'
import core, { Doc, matchQuery, Ref, Timestamp } from '@hcengineering/core'
import { Execution, parseContext } from '@hcengineering/process'
import { ProcessControl } from '@hcengineering/server-process'
import { markupToText } from '@hcengineering/text-core'
import { getContextValue } from './utils'
import cardPlugin from '@hcengineering/card'
// #region ArrayReduce
@@ -573,4 +574,12 @@ export function DayFromDate (value: Date): number {
return new Date(value).getDate()
}
export function StringFromMarkup (value: string): string {
return markupToText(value)
}
export function MarkupFromString (value: string): string {
return value
}
// #endregion
+2
View File
@@ -119,11 +119,13 @@ export default plugin(serverProcessId, {
ExecutionStarted: '' as Resource<TransformFunc>,
StringFromNumber: '' as Resource<TransformFunc>,
StringFromDate: '' as Resource<TransformFunc>,
StringFromMarkup: '' as Resource<TransformFunc>,
StringFromBoolean: '' as Resource<TransformFunc>,
NumberFromDate: '' as Resource<TransformFunc>,
DateFromNumber: '' as Resource<TransformFunc>,
NumberFromString: '' as Resource<TransformFunc>,
DateFromString: '' as Resource<TransformFunc>,
MarkupFromString: '' as Resource<TransformFunc>,
YearFromDate: '' as Resource<TransformFunc>,
MonthFromDate: '' as Resource<TransformFunc>,
DayFromDate: '' as Resource<TransformFunc>,