mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-13 21:27:46 +02:00
feat: Implement process import/export functionality, enhance process … (#10528)
Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
@@ -18,9 +18,10 @@
|
||||
import { translate } from '@hcengineering/platform'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { Process, State } from '@hcengineering/process'
|
||||
import { ButtonIcon, getCurrentLocation, Icon, IconAdd, Label, navigate } from '@hcengineering/ui'
|
||||
import { ButtonIcon, getCurrentLocation, Icon, IconAdd, IconFile, IconOpen, Label, navigate } from '@hcengineering/ui'
|
||||
import process from '../plugin'
|
||||
import { makeRank } from '@hcengineering/rank'
|
||||
import { importProcess } from '../exporter'
|
||||
|
||||
export let masterTag: MasterTag
|
||||
|
||||
@@ -76,12 +77,35 @@
|
||||
loc.path[6] = id
|
||||
navigate(loc, true)
|
||||
}
|
||||
|
||||
function handleImport (): void {
|
||||
const input = document.createElement('input')
|
||||
input.type = 'file'
|
||||
input.accept = '.json'
|
||||
input.onchange = async (evt) => {
|
||||
const file = (evt.target as HTMLInputElement).files?.[0]
|
||||
if (file != null) {
|
||||
const text = await file.text()
|
||||
await importProcess(masterTag._id, text)
|
||||
}
|
||||
}
|
||||
input.click()
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="hulyTableAttr-header font-medium-12">
|
||||
<Icon icon={process.icon.Process} size="small" />
|
||||
<span><Label label={process.string.Processes} /></span>
|
||||
<ButtonIcon kind="primary" icon={IconAdd} size="small" dataId={'btnAdd'} on:click={add} />
|
||||
<div class="flex-row-center flex-gap-1">
|
||||
<ButtonIcon
|
||||
kind="primary"
|
||||
icon={IconFile}
|
||||
size="small"
|
||||
tooltip={{ label: process.string.Import, direction: 'bottom' }}
|
||||
on:click={handleImport}
|
||||
/>
|
||||
<ButtonIcon kind="primary" icon={IconAdd} size="small" dataId={'btnAdd'} on:click={add} />
|
||||
</div>
|
||||
</div>
|
||||
{#if processes.length}
|
||||
<div class="hulyTableAttr-content task">
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Ref, SortingOrder } from '@hcengineering/core'
|
||||
import { createQuery, getClient, MessageBox } from '@hcengineering/presentation'
|
||||
import { createQuery, getClient, MessageBox, IconDownload } from '@hcengineering/presentation'
|
||||
import { Process, State, Transition } from '@hcengineering/process'
|
||||
import { clearSettingsStore, settingsStore } from '@hcengineering/setting-resources'
|
||||
import {
|
||||
@@ -30,6 +30,7 @@
|
||||
secondNavSeparators,
|
||||
showPopup
|
||||
} from '@hcengineering/ui'
|
||||
import { exportProcess } from '../../exporter'
|
||||
import view from '@hcengineering/view'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import process from '../../plugin'
|
||||
@@ -135,6 +136,24 @@
|
||||
function handleSettings (): void {
|
||||
showPopup(ProcesssSetting, { value })
|
||||
}
|
||||
|
||||
function handleExport (): void {
|
||||
if (value === undefined) return
|
||||
const str = JSON.stringify(
|
||||
exportProcess(value).docs.map((doc) => {
|
||||
const { modifiedBy, modifiedOn, createdBy, createdOn, ...rest } = doc
|
||||
return rest
|
||||
})
|
||||
)
|
||||
const blob = new Blob([str], { type: 'application/json' })
|
||||
const url = URL.createObjectURL(blob)
|
||||
const link = document.createElement('a')
|
||||
link.href = url
|
||||
link.download = `${value.name}.json`
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="hulyComponent-content__container columns">
|
||||
@@ -153,6 +172,13 @@
|
||||
/>
|
||||
<div class="flex-row-center flex-gap-2">
|
||||
<ButtonIcon icon={IconSettings} size="small" kind="secondary" on:click={handleSettings} />
|
||||
<ButtonIcon
|
||||
icon={IconDownload}
|
||||
tooltip={{ label: process.string.Export, direction: 'bottom' }}
|
||||
size="small"
|
||||
kind="secondary"
|
||||
on:click={handleExport}
|
||||
/>
|
||||
<ButtonIcon
|
||||
icon={IconDetails}
|
||||
tooltip={{ label: process.string.Data, direction: 'bottom' }}
|
||||
|
||||
@@ -15,13 +15,11 @@
|
||||
<script lang="ts">
|
||||
import { Ref } from '@hcengineering/core'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { Process, State } from '@hcengineering/process'
|
||||
import { Process } from '@hcengineering/process'
|
||||
import { DropdownLabels, Label } from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import plugin from '../../plugin'
|
||||
import { ModeId, Modes } from '../../query'
|
||||
import { getContext } from '../../utils'
|
||||
import BaseCriteria from '../criterias/BaseCriteria.svelte'
|
||||
import { ModeId } from '../../query'
|
||||
import SubProcessStateCriteria from '../criterias/SubProcessStateCriteria.svelte'
|
||||
|
||||
export let readonly: boolean
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { type MasterTag } from '@hcengineering/card'
|
||||
import { type Class, type Doc, type Ref } from '@hcengineering/core'
|
||||
import core, { type Doc, type Ref, type Class, generateId } from '@hcengineering/core'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import process from './plugin'
|
||||
|
||||
export function exportProcess (_id: Ref<MasterTag>): {
|
||||
export function exportProcesses (_id: Ref<MasterTag>): {
|
||||
docs: Doc[]
|
||||
required: Array<Ref<Class<Doc>>>
|
||||
} {
|
||||
@@ -12,11 +12,48 @@ export function exportProcess (_id: Ref<MasterTag>): {
|
||||
const m = client.getModel()
|
||||
const processes = m.findAllSync(process.class.Process, { masterTag: _id })
|
||||
for (const proc of processes) {
|
||||
docs.push(proc)
|
||||
|
||||
docs.push(...m.findAllSync(process.class.State, { process: proc._id }))
|
||||
|
||||
docs.push(...m.findAllSync(process.class.Transition, { process: proc._id }))
|
||||
const res = exportProcess(proc)
|
||||
docs.push(...res.docs)
|
||||
}
|
||||
return { docs, required: [] }
|
||||
}
|
||||
|
||||
export function exportProcess (proc: Doc): {
|
||||
docs: Doc[]
|
||||
required: Array<Ref<Class<Doc>>>
|
||||
} {
|
||||
const docs: Doc[] = [proc]
|
||||
const client = getClient()
|
||||
const m = client.getModel()
|
||||
|
||||
docs.push(...m.findAllSync(process.class.State, { process: proc._id as any }))
|
||||
docs.push(...m.findAllSync(process.class.Transition, { process: proc._id as any }))
|
||||
|
||||
return { docs, required: [] }
|
||||
}
|
||||
|
||||
export async function importProcess (masterTag: Ref<MasterTag>, json: string): Promise<void> {
|
||||
try {
|
||||
const data = JSON.parse(json) as Doc[]
|
||||
if (data[0] === undefined) return
|
||||
const client = getClient()
|
||||
const m = client.getModel()
|
||||
const apply = client.apply('Import process')
|
||||
;(data[0] as any).masterTag = masterTag
|
||||
;(data[0] as any)._id = generateId()
|
||||
for (const elem of data) {
|
||||
if (m.findObject(elem._id) !== undefined) continue
|
||||
await apply.createDoc(elem._class, core.space.Model, stripData(elem), elem._id)
|
||||
}
|
||||
await apply.commit(true)
|
||||
} catch (e) {
|
||||
console.error('Failed to import process:', e)
|
||||
}
|
||||
}
|
||||
|
||||
function stripData<T extends Doc> (
|
||||
doc: T
|
||||
): Omit<T, '_id' | '_class' | 'space' | 'modifiedBy' | 'modifiedOn' | 'createdBy' | 'createdOn'> {
|
||||
const { _id, _class, space, modifiedBy, modifiedOn, createdBy, createdOn, ...rest } = doc
|
||||
return rest
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
import { type Resources } from '@hcengineering/platform'
|
||||
import ApproveRequestPresenter from './components/ApproveRequestPresenter.svelte'
|
||||
import ExecutionContextSelector from './components/attributeEditors/ExecutionContextSelector.svelte'
|
||||
import FunctionSelector from './components/attributeEditors/FunctionSelector.svelte'
|
||||
import NestedContextSelector from './components/attributeEditors/NestedContextSelector.svelte'
|
||||
@@ -24,20 +25,19 @@ import ExecutionMyToDos from './components/ExecutionMyToDos.svelte'
|
||||
import ExecutonPresenter from './components/ExecutonPresenter.svelte'
|
||||
import ExecutonProgressPresenter from './components/ExecutonProgressPresenter.svelte'
|
||||
import Main from './components/Main.svelte'
|
||||
import CancelToDoEditor from './components/settings/CancelToDoEditor.svelte'
|
||||
import ApproveRequestPresenter from './components/ApproveRequestPresenter.svelte'
|
||||
import SubProcessPresenter from './components/presenters/SubProcessPresenter.svelte'
|
||||
import ToDoPresenter from './components/presenters/ToDoPresenter.svelte'
|
||||
import UpdateCardPresenter from './components/presenters/UpdateCardPresenter.svelte'
|
||||
import ProcessesCardSection from './components/ProcessesCardSection.svelte'
|
||||
import ProcessesExtension from './components/ProcessesExtension.svelte'
|
||||
import RequestsCardSection from './components/RequestsCardSection.svelte'
|
||||
import RequestsExtension from './components/RequestsExtension.svelte'
|
||||
import ProcessesSettingSection from './components/ProcessesSection.svelte'
|
||||
import ProcessPresenter from './components/ProcessPresenter.svelte'
|
||||
import RequestsCardSection from './components/RequestsCardSection.svelte'
|
||||
import RequestsExtension from './components/RequestsExtension.svelte'
|
||||
import RunProcessCardPopup from './components/RunProcessCardPopup.svelte'
|
||||
import RunProcessPopup from './components/RunProcessPopup.svelte'
|
||||
import ActionsPresenter from './components/settings/ActionsPresenter.svelte'
|
||||
import CancelToDoEditor from './components/settings/CancelToDoEditor.svelte'
|
||||
import FunctionSubmenu from './components/settings/FunctionSubmenu.svelte'
|
||||
import ProcessEditor from './components/settings/ProcessEditor.svelte'
|
||||
import StatePresenter from './components/settings/StatePresenter.svelte'
|
||||
@@ -65,21 +65,22 @@ import CreateCardPresenter from './components/presenters/CreateCardPresenter.sve
|
||||
import ProcessesHeaderExtension from './components/ProcessesHeaderExtension.svelte'
|
||||
import AddRelationEditor from './components/settings/AddRelationEditor.svelte'
|
||||
import AddTagEditor from './components/settings/AddTagEditor.svelte'
|
||||
import ApproveRequestEditor from './components/settings/ApproveRequestEditor.svelte'
|
||||
import ApproveRequestTriggerEditor from './components/settings/ApproveRequestTriggerEditor.svelte'
|
||||
import ApproveRequestTriggerPresenter from './components/settings/ApproveRequestTriggerPresenter.svelte'
|
||||
import CardUpdateEditor from './components/settings/CardUpdateEditor.svelte'
|
||||
import CardUpdatePresenter from './components/settings/CardUpdatePresenter.svelte'
|
||||
import CreateCardEditor from './components/settings/CreateCardEditor.svelte'
|
||||
import FieldChangesEditor from './components/settings/FieldChangesEditor.svelte'
|
||||
import LockSectionEditor from './components/settings/LockSectionEditor.svelte'
|
||||
import LockSectionPresenter from './components/settings/LockSectionPresenter.svelte'
|
||||
import SubProcessMatchEditor from './components/settings/SubProcessMatchEditor.svelte'
|
||||
import SubProcessMatchPresenter from './components/settings/SubProcessMatchPresenter.svelte'
|
||||
import TimeEditor from './components/settings/TimeEditor.svelte'
|
||||
import TimePresenter from './components/settings/TimePresenter.svelte'
|
||||
import ToDoSettingPresenter from './components/settings/ToDoPresenter.svelte'
|
||||
import ToDoValuePresenter from './components/settings/ToDoValuePresenter.svelte'
|
||||
import TransitionRefPresenter from './components/settings/TransitionRefPresenter.svelte'
|
||||
import ApproveRequestEditor from './components/settings/ApproveRequestEditor.svelte'
|
||||
import ApproveRequestTriggerEditor from './components/settings/ApproveRequestTriggerEditor.svelte'
|
||||
import ApproveRequestTriggerPresenter from './components/settings/ApproveRequestTriggerPresenter.svelte'
|
||||
import LockSectionEditor from './components/settings/LockSectionEditor.svelte'
|
||||
import LockSectionPresenter from './components/settings/LockSectionPresenter.svelte'
|
||||
import UnLockSectionPresenter from './components/settings/UnLockSectionPresenter.svelte'
|
||||
import AppendEditor from './components/transformEditors/AppendEditor.svelte'
|
||||
import CutEditor from './components/transformEditors/CutEditor.svelte'
|
||||
@@ -87,8 +88,7 @@ import ReplaceEditor from './components/transformEditors/ReplaceEditor.svelte'
|
||||
import SplitEditor from './components/transformEditors/SplitEditor.svelte'
|
||||
import NumberPresenter from './components/transformPresenters/NumberPresenter.svelte'
|
||||
import RolePresenter from './components/transformPresenters/RolePresenter.svelte'
|
||||
import ToDoValuePresenter from './components/settings/ToDoValuePresenter.svelte'
|
||||
import { exportProcess } from './exporter'
|
||||
import { exportProcesses, importProcess } from './exporter'
|
||||
import { ProcessMiddleware } from './middleware'
|
||||
import {
|
||||
approveRequestApproved,
|
||||
@@ -207,7 +207,8 @@ export default async (): Promise<Resources> => ({
|
||||
ApproveRequestRejected: approveRequestRejected
|
||||
},
|
||||
function: {
|
||||
ExportProcess: exportProcess,
|
||||
ExportProcess: exportProcesses,
|
||||
ImportProcess: importProcess,
|
||||
ShowDoneQuery: showDoneQuery,
|
||||
CheckProcessSectionVisibility: checkProcessSectionVisibility,
|
||||
CheckRequestsSectionVisibility: checkRequestsSectionVisibility,
|
||||
|
||||
@@ -249,7 +249,9 @@ export default mergeIds(processId, process, {
|
||||
LockCard: '' as IntlString,
|
||||
LockSection: '' as IntlString,
|
||||
UnlockCard: '' as IntlString,
|
||||
UnlockSection: '' as IntlString
|
||||
UnlockSection: '' as IntlString,
|
||||
Export: '' as IntlString,
|
||||
Import: '' as IntlString
|
||||
},
|
||||
permission: {
|
||||
RunProcess: '' as Ref<Permission>,
|
||||
|
||||
Reference in New Issue
Block a user