Skip to content
Merged

ID type #10126

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions models/core/src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
type Collection,
type Configuration,
type ConfigurationElement,
type CustomSequence,
type Doc,
type Domain,
DOMAIN_BLOB,
Expand Down Expand Up @@ -257,6 +258,12 @@ export class TTypeIntlString extends TType {}
@Model(core.class.TypeNumber, core.class.Type)
export class TTypeNumber extends TType {}

@UX(core.string.Id)
@Model(core.class.TypeIdentifier, core.class.Type)
export class TTypeIdentifier extends TType {
of!: Ref<Sequence>
}

@UX(core.string.BlobSize)
@Model(core.class.TypeFileSize, core.class.Type)
export class TTypeFileSize extends TType {}
Expand Down Expand Up @@ -397,6 +404,11 @@ export class TSequence extends TDoc implements Sequence {
sequence!: number
}

@Model(core.class.CustomSequence, core.class.Sequence)
export class TCustomSequence extends TSequence implements CustomSequence {
prefix!: string
}

@Model(core.class.ClassCollaborators, core.class.Doc, DOMAIN_MODEL)
export class TClassCollaborators extends TDoc implements ClassCollaborators<Doc> {
attachedTo!: Ref<Class<Doc>>
Expand Down
4 changes: 4 additions & 0 deletions models/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,15 @@ import {
TTypePersonId,
TTypeAccountUuid,
TTypeNumber,
TTypeIdentifier,
TTypeRank,
TTypeRecord,
TTypeRelatedDocument,
TTypeString,
TTypeTimestamp,
TVersion,
TSequence,
TCustomSequence,
TClassCollaborators,
TCollaborator
} from './core'
Expand Down Expand Up @@ -135,6 +137,7 @@ export function createModel (builder: Builder): void {
TTypeFileSize,
TTypeTimestamp,
TTypeNumber,
TTypeIdentifier,
TTypeBoolean,
TTypeString,
TTypeRank,
Expand All @@ -155,6 +158,7 @@ export function createModel (builder: Builder): void {
TIndexConfiguration,
TStatus,
TSequence,
TCustomSequence,
TDomainStatusPlaceholder,
TStatusCategory,
TMigrationState,
Expand Down
4 changes: 4 additions & 0 deletions models/setting/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,10 @@ export function createModel (builder: Builder): void {
editor: setting.component.NumberTypeEditor
})

builder.mixin(core.class.TypeIdentifier, core.class.Class, view.mixin.ObjectEditor, {
editor: setting.component.IdentifierTypeEditor
})

builder.mixin(core.class.RefTo, core.class.Class, view.mixin.ObjectEditor, {
editor: setting.component.RefEditor
})
Expand Down
1 change: 1 addition & 0 deletions models/setting/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export default mergeIds(settingId, setting, {
HyperlinkTypeEditor: '' as AnyComponent,
BooleanTypeEditor: '' as AnyComponent,
NumberTypeEditor: '' as AnyComponent,
IdentifierTypeEditor: '' as AnyComponent,
DateTypeEditor: '' as AnyComponent,
RefEditor: '' as AnyComponent,
AssociationEditor: '' as AnyComponent,
Expand Down
1 change: 1 addition & 0 deletions models/view/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,7 @@ export function createModel (builder: Builder): void {
)
classPresenter(builder, core.class.TypeIntlString, view.component.IntlStringPresenter)
classPresenter(builder, core.class.TypeNumber, view.component.NumberPresenter, view.component.NumberEditor)
classPresenter(builder, core.class.TypeIdentifier, view.component.IdPresenter, view.component.IdPresenter)
classPresenter(
builder,
core.class.TypeMarkup,
Expand Down
2 changes: 1 addition & 1 deletion plugins/client-resources/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"@hcengineering/client": "^0.7.3",
"@hcengineering/communication-sdk-types": "^0.7.5",
"@hcengineering/communication-types": "^0.7.7",
"@hcengineering/core": "^0.7.8",
"@hcengineering/core": "^0.7.10",
"@hcengineering/platform": "^0.7.5",
"@hcengineering/rpc": "^0.7.3",
"snappyjs": "^0.7.0"
Expand Down
2 changes: 1 addition & 1 deletion plugins/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
},
"dependencies": {
"@hcengineering/platform": "^0.7.5",
"@hcengineering/core": "^0.7.8"
"@hcengineering/core": "^0.7.10"
},
"repository": "https://github.com/hcengineering/platform",
"publishConfig": {
Expand Down
3 changes: 2 additions & 1 deletion plugins/setting-assets/lang/cs.json
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@
"DangerZone": "Nebezpečná zóna",
"ApiAccess": "Přístup k API",
"ApiToken": "API token",
"GenerateApiToken": "Vygenerovat API token"
"GenerateApiToken": "Vygenerovat API token",
"IdentifierExists": "Identifikátor již existuje"
}
}
3 changes: 2 additions & 1 deletion plugins/setting-assets/lang/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@
"DangerZone": "Gefahrenzone",
"ApiAccess": "API-Zugriff",
"ApiToken": "API-Token",
"GenerateApiToken": "API-Token generieren"
"GenerateApiToken": "API-Token generieren",
"IdentifierExists": "Bezeichner existiert bereits"
}
}
3 changes: 2 additions & 1 deletion plugins/setting-assets/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@
"DangerZone": "Danger zone",
"ApiAccess": "API access",
"ApiToken": "API token",
"GenerateApiToken": "Generate API token"
"GenerateApiToken": "Generate API token",
"IdentifierExists": "Identifier already exists"
}
}
3 changes: 2 additions & 1 deletion plugins/setting-assets/lang/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@
"DangerZone": "Zona de peligro",
"ApiAccess": "Acceso API",
"ApiToken": "Token API",
"GenerateApiToken": "Generar token API"
"GenerateApiToken": "Generar token API",
"IdentifierExists": "El identificador ya existe"
}
}
3 changes: 2 additions & 1 deletion plugins/setting-assets/lang/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@
"DangerZone": "Zone dangereuse",
"ApiAccess": "Accès API",
"ApiToken": "Token API",
"GenerateApiToken": "Générer un token API"
"GenerateApiToken": "Générer un token API",
"IdentifierExists": "Identifiant déjà utilisé"
}
}
3 changes: 2 additions & 1 deletion plugins/setting-assets/lang/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@
"DangerZone": "Zona pericolosa",
"ApiAccess": "Accesso API",
"ApiToken": "Token API",
"GenerateApiToken": "Genera token API"
"GenerateApiToken": "Genera token API",
"IdentifierExists": "Identificatore già esistente"
}
}
3 changes: 2 additions & 1 deletion plugins/setting-assets/lang/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@
"DangerZone": "危険ゾーン",
"ApiAccess": "APIアクセス",
"ApiToken": "APIトークン",
"GenerateApiToken": "APIトークンを生成"
"GenerateApiToken": "APIトークンを生成",
"IdentifierExists": "識別子は既に存在します"
}
}
3 changes: 2 additions & 1 deletion plugins/setting-assets/lang/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@
"DangerZone": "Zona de perigo",
"ApiAccess": "Acesso à API",
"ApiToken": "Token de API",
"GenerateApiToken": "Gerar token de API"
"GenerateApiToken": "Gerar token de API",
"IdentifierExists": "Identificador já existe"
}
}
1 change: 1 addition & 0 deletions plugins/setting-assets/lang/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"MinValue": "Минимальное значение",
"MaxValue": "Максимальное значение",
"IntegerOnly": "Только целые числа",
"IdentifierExists": "\u0418\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442",
"AccountSettings": "Настройки аккаунта",
"Categories": "Категории",
"Delete": "Удалить",
Expand Down
3 changes: 2 additions & 1 deletion plugins/setting-assets/lang/tr.json
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@
"DangerZone": "Tehlike bölgesi",
"ApiAccess": "API erişimi",
"ApiToken": "API token",
"GenerateApiToken": "API token oluştur"
"GenerateApiToken": "API token oluştur",
"IdentifierExists": "Tanımlayıcı zaten mevcut"
}
}
3 changes: 2 additions & 1 deletion plugins/setting-assets/lang/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@
"DangerZone": "危险区域",
"ApiAccess": "API访问",
"ApiToken": "API令牌",
"GenerateApiToken": "生成API令牌"
"GenerateApiToken": "生成API令牌",
"IdentifierExists": "标识符已存在"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<!--
// Copyright © 2022 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 core, { CustomSequence, Ref, TypeIdentifier as TypeId } from '@hcengineering/core'
import { TypeIdentifier } from '@hcengineering/model'
import { createQuery, getClient } from '@hcengineering/presentation'
import { EditBox, Label } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import setting from '../../plugin'

export let type: TypeId | undefined
export let editable: boolean = true

const dispatch = createEventDispatcher()
const client = getClient()

let seq: Ref<CustomSequence> | undefined = type?.of

let identifier: string = ''
let sequences: CustomSequence[] = []

$: identifiers = new Set(sequences.filter((p) => p._id !== seq).map((s) => s.prefix.toUpperCase()))

const query = createQuery()
query.query(core.class.CustomSequence, {}, (res) => {
sequences = res
identifier = seq ? (sequences.find((s) => s._id === seq)?.prefix ?? '') : ''
})

$: currentSequence = sequences.find((s) => s._id === seq)

async function change () {
if (!editable) return
if (identifiers.has(identifier.toUpperCase())) return
if (identifier.toUpperCase() === (currentSequence?.prefix?.toUpperCase() ?? '')) return
if (currentSequence !== undefined) {
await client.update(currentSequence, { prefix: identifier.toUpperCase() })
} else {
const newSeq = await client.createDoc(core.class.CustomSequence, core.space.Workspace, {
prefix: identifier.toUpperCase(),
sequence: 0,
attachedTo: core.class.CustomSequence
})
seq = newSeq
dispatch('change', { type: TypeIdentifier(newSeq) })
}
}
</script>

<span class="label">
<Label label={core.string.Id} />
</span>
<div class="flex-row-center">
<EditBox
bind:value={identifier}
disabled={!editable}
placeholder={core.string.Id}
uppercase
maxWidth={'50%'}
on:change={change}
/>
{#if editable && identifiers.has(identifier.toUpperCase())}
<div class="overflow-label duplicated-identifier">
<Label label={setting.string.IdentifierExists} />
</div>
{/if}
</div>

<style lang="scss">
.duplicated-identifier {
color: var(--theme-warning-color);
}
</style>
2 changes: 2 additions & 0 deletions plugins/setting-resources/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import EnumTypeEditor from './components/typeEditors/EnumTypeEditor.svelte'
import HyperlinkTypeEditor from './components/typeEditors/HyperlinkTypeEditor.svelte'
import NumberTypeEditor from './components/typeEditors/NumberTypeEditor.svelte'
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 StringTypeEditor from './components/typeEditors/StringTypeEditor.svelte'
Expand Down Expand Up @@ -122,6 +123,7 @@ export default async (): Promise<Resources> => ({
HyperlinkTypeEditor,
BooleanTypeEditor,
NumberTypeEditor,
IdentifierTypeEditor,
RefEditor,
RelationSetting,
DateTypeEditor,
Expand Down
3 changes: 2 additions & 1 deletion plugins/setting-resources/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ export default mergeIds(settingId, setting, {
ReleasePrimarySocialId: '' as IntlString,
ReleasePrimarySocialIdConfirm: '' as IntlString,
Login: '' as IntlString,
Primary: '' as IntlString
Primary: '' as IntlString,
IdentifierExists: '' as IntlString
}
})
33 changes: 33 additions & 0 deletions plugins/view-resources/src/components/IdPresenter.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<!--
// 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 { getEmbeddedLabel } from '@hcengineering/platform'
import { LabelAndProps, tooltip } from '@hcengineering/ui'

export let value: string | undefined

$: tooltipParams = getTooltip(value)

function getTooltip (value: string | undefined): LabelAndProps | undefined {
if (value === undefined) return
return {
label: getEmbeddedLabel(value)
}
}
</script>

<span class="overflow-label" use:tooltip={tooltipParams}>
{value ?? ''}
</span>
2 changes: 2 additions & 0 deletions plugins/view-resources/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import ObjectMention from './components/ObjectMention.svelte'
import ObjectPresenter from './components/ObjectPresenter.svelte'
import PersonArrayEditor from './components/PersonArrayEditor.svelte'
import PersonIdPresenter from './components/PersonIdPresenter.svelte'
import IdPresenter from './components/IdPresenter.svelte'
import ReadOnlyNotification from './components/ReadOnlyNotification.svelte'
import RolePresenter from './components/RolePresenter.svelte'
import SearchSelector from './components/SearchSelector.svelte'
Expand Down Expand Up @@ -274,6 +275,7 @@ export default async (): Promise<Resources> => ({
TimestampFilter,
TableBrowser,
SpacePresenter,
IdPresenter,
StringEditor,
StringPresenter,
HyperlinkPresenter,
Expand Down
3 changes: 2 additions & 1 deletion plugins/view-resources/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ export default mergeIds(viewId, view, {
SpaceTypeSelector: '' as AnyComponent,
MasterDetailBrowser: '' as AnyComponent,
NumberEditor: '' as AnyComponent,
NumberPresenter: '' as AnyComponent
NumberPresenter: '' as AnyComponent,
IdPresenter: '' as AnyComponent
},
string: {
Contains: '' as IntlString,
Expand Down
2 changes: 2 additions & 0 deletions server/server-pipeline/src/pipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
MarkDerivedEntryMiddleware,
ModelMiddleware,
ModifiedMiddleware,
IdentifierMiddleware,
NormalizeTxMiddleware,
PluginConfigurationMiddleware,
PrivateMiddleware,
Expand Down Expand Up @@ -154,6 +155,7 @@ export function createServerPipeline (
: []),
UserStatusMiddleware.create,
ApplyTxMiddleware.create, // Extract apply
IdentifierMiddleware.create, // After ApplyTx to ensure that it pass
TxMiddleware.create, // Store tx into transaction domain
...(opt.disableTriggers === true ? [] : [TriggersMiddleware.create]),
...(opt.fulltextUrl !== undefined
Expand Down
Loading