EZQMS-1392: Obsolete documents (#7833)

Signed-off-by: Victor Ilyushchenko <alt13ri@gmail.com>
This commit is contained in:
Victor Ilyushchenko
2025-01-29 17:18:46 +03:00
committed by GitHub
parent 7ae937461f
commit 984c7d90ab
20 changed files with 143 additions and 23 deletions
+27 -4
View File
@@ -150,6 +150,7 @@ export function createModel (builder: Builder): void {
['inProgress', documents.string.InProgress, {}],
['effective', documents.string.Effective, {}],
['archived', documents.string.Archived, {}],
['obsolete', documents.string.Obsolete, {}],
['all', documents.string.All, {}]
]
}
@@ -170,6 +171,7 @@ export function createModel (builder: Builder): void {
['effective', documents.string.Effective, {}],
['inProgress', documents.string.InProgress, {}],
['archived', documents.string.Archived, {}],
['obsolete', documents.string.Obsolete, {}],
['all', documents.string.All, {}]
]
}
@@ -774,16 +776,37 @@ export function createModel (builder: Builder): void {
documents.action.DeleteDocument
)
// createAction(
// builder,
// {
// action: documents.actionImpl.ArchiveDocument,
// label: view.string.Archive,
// icon: view.icon.Archive,
// input: 'any',
// category: view.category.General,
// target: documents.class.Document,
// visibilityTester: documents.function.CanArchiveDocument,
// query: {
// state: DocumentState.Effective
// },
// context: {
// mode: ['context', 'browser'],
// group: 'remove'
// }
// },
// documents.action.ArchiveDocument
// )
createAction(
builder,
{
action: documents.actionImpl.ArchiveDocument,
label: view.string.Archive,
action: documents.actionImpl.MakeDocumentObsolete,
label: documents.string.MakeDocumentObsolete,
icon: view.icon.Archive,
input: 'any',
category: view.category.General,
target: documents.class.Document,
visibilityTester: documents.function.CanArchiveDocument,
visibilityTester: documents.function.CanMakeDocumentObsolete,
query: {
state: DocumentState.Effective
},
@@ -792,7 +815,7 @@ export function createModel (builder: Builder): void {
group: 'remove'
}
},
documents.action.ArchiveDocument
documents.action.MakeDocumentObsolete
)
createAction(
@@ -68,6 +68,7 @@ export default mergeIds(documentsId, documents, {
TransferTemplate: '' as ViewAction,
DeleteDocument: '' as ViewAction,
ArchiveDocument: '' as ViewAction,
MakeDocumentObsolete: '' as ViewAction,
TransferDocument: '' as ViewAction,
EditDocSpace: '' as ViewAction
},
@@ -295,7 +295,12 @@
"CreateFolder": "Vytvořit novou složku",
"RenameFolder": "Přejmenovat složku",
"CreateChildFolder": "Vytvořit podsložku"
"CreateChildFolder": "Vytvořit podsložku",
"Obsolete": "Zastaralé",
"MakeDocumentObsolete": "Označit jako zastaralé",
"MakeDocumentObsoleteDialog": "Označit {count, plural, one {dokument jako zastaralý} other {dokumenty jako zastaralé}}",
"MakeDocumentObsoleteConfirm": "Opravdu chcete označit následující dokumenty jako zastaralé: {titles}?"
},
"controlledDocStates": {
"Empty": "",
@@ -302,7 +302,12 @@
"CreateFolder": "Neuen Ordner erstellen",
"RenameFolder": "Ordner umbenennen",
"CreateChildFolder": "Unterordner erstellen"
"CreateChildFolder": "Unterordner erstellen",
"Obsolete": "Veraltet",
"MakeDocumentObsolete": "Als veraltet markieren",
"MakeDocumentObsoleteDialog": "{count, plural, one {Dokument als veraltet markieren} other {Dokumente als veraltet markieren}}",
"MakeDocumentObsoleteConfirm": "Möchten Sie die folgenden Dokumente wirklich als veraltet markieren: {titles}?"
},
"controlledDocStates": {
"Empty": "",
@@ -119,6 +119,11 @@
"Archived": "Archived",
"Deleted": "Deleted",
"MetaAbstract": "Abstract",
"Obsolete": "Obsolete",
"MakeDocumentObsolete": "Mark as obsolete",
"MakeDocumentObsoleteDialog": "Mark {count, plural, =0 {document} other {documents}} as obsolete",
"MakeDocumentObsoleteConfirm": "Do you really want to mark the following documents as obsolete: {titles}?",
"ContentTab": "Content",
"TeamTab": "Team",
@@ -262,7 +262,12 @@
"CreateFolder": "Créer un nouveau dossier",
"RenameFolder": "Renommer le dossier",
"CreateChildFolder": "Créer un sous-dossier"
"CreateChildFolder": "Créer un sous-dossier",
"Obsolete": "Obsolète",
"MakeDocumentObsolete": "Marquer comme obsolète",
"MakeDocumentObsoleteDialog": "Marquer {count, plural, one {le document comme obsolète} other {les documents comme obsolètes}}",
"MakeDocumentObsoleteConfirm": "Voulez-vous vraiment marquer les documents suivants comme obsolètes : {titles} ?"
},
"controlledDocStates": {
"Empty": "",
@@ -260,7 +260,12 @@
"CreateFolder": "Crea nuova cartella",
"RenameFolder": "Rinomina cartella",
"CreateChildFolder": "Crea sottocartella"
"CreateChildFolder": "Crea sottocartella",
"Obsolete": "Obsoleto",
"MakeDocumentObsolete": "Segna come obsoleto",
"MakeDocumentObsoleteDialog": "Segna {count, plural, one {il documento come obsoleto} other {i documenti come obsoleti}}",
"MakeDocumentObsoleteConfirm": "Vuoi davvero segnare i seguenti documenti come obsoleti: {titles}?"
},
"controlledDocStates": {
"Empty": "",
@@ -304,7 +304,12 @@
"CreateFolder": "Создать новую папку",
"RenameFolder": "Переименовать папку",
"CreateChildFolder": "Создать подпапку"
"CreateChildFolder": "Создать подпапку",
"Obsolete": "Устаревший",
"MakeDocumentObsolete": "Пометить как устаревшее",
"MakeDocumentObsoleteDialog": "Пометить {count, plural, one {документ как устаревший} other {документы как устаревшие}}",
"MakeDocumentObsoleteConfirm": "Вы действительно хотите пометить следующие документы как устаревшие: {titles}?"
},
"controlledDocStates": {
"Empty": "",
@@ -301,7 +301,12 @@
"CreateFolder": "创建新文件夹",
"RenameFolder": "重命名文件夹",
"CreateChildFolder": "创建子文件夹"
"CreateChildFolder": "创建子文件夹",
"Obsolete": "已过时",
"MakeDocumentObsolete": "标记为过时",
"MakeDocumentObsoleteDialog": "标记 {count, plural, one {文档为过时} other {文档为过时}}",
"MakeDocumentObsoleteConfirm": "您确定要将以下文档标记为过时吗:{titles}?"
},
"controlledDocStates": {
"Empty": "",
@@ -57,9 +57,10 @@
$: inProgress = { state: { $in: [DocumentState.Draft] }, space: { $in: spaces } }
$: effective = { state: { $in: [DocumentState.Effective] }, space: { $in: spaces } }
$: archived = { state: { $in: [DocumentState.Archived, DocumentState.Deleted] }, space: { $in: spaces } }
$: obsolete = { state: { $in: [DocumentState.Obsolete] }, space: { $in: spaces } }
$: all = { space: { $in: spaces } }
$: queries = { inProgress, effective, archived, all }
$: queries = { inProgress, effective, archived, obsolete, all }
$: mode = $resolvedLocationStore.query?.mode ?? undefined
$: if (mode === undefined || (queries as any)[mode] === undefined) {
@@ -118,6 +118,7 @@
DocumentState.Archived,
DocumentState.Deleted,
DocumentState.Effective,
DocumentState.Obsolete,
ControlledDocumentState.InApproval,
ControlledDocumentState.Approved,
ControlledDocumentState.ToReview
@@ -37,11 +37,11 @@
}
&.obsolete {
background: var(--theme-state-ghost-background-color);
border-color: var(--theme-state-ghost-border-color);
background: var(--theme-state-negative-background-color);
border-color: var(--theme-state-negative-border-color);
.label {
color: var(--theme-state-ghost-color);
color: var(--theme-state-negative-color);
}
}
@@ -148,9 +148,10 @@
{@const title = doc ? getDocumentName(doc) : meta?.title ?? ''}
{@const docid = doc?._id ?? prjdoc._id}
{@const isFolder = prjdoc.document === documents.ids.Folder}
{@const isObsolete = doc ? doc.state === DocumentState.Obsolete : false}
{@const children = metaid ? childrenByParent[metaid] ?? [] : []}
{#if metaid}
{@const children = childrenByParent[metaid] ?? []}
{#if metaid && (!isObsolete || children.length > 0)}
{@const isDraggedOver = draggedOver === metaid}
<div class="flex-col relative">
{#if isDraggedOver}
@@ -160,12 +161,12 @@
_id={docid}
icon={isFolder ? documents.icon.Folder : documents.icon.Document}
iconProps={{
fill: 'currentColor'
fill: isObsolete ? 'var(--dangerous-bg-color)' : 'currentColor'
}}
{title}
selected={selected === docid || selected === prjdoc._id}
isFold
empty={children.length === 0 || children === undefined}
empty={children.length === 0}
actions={getMoreActions !== undefined ? () => getDocMoreActions(prjdoc) : undefined}
{level}
{collapsedPrefix}
@@ -38,6 +38,9 @@
case DocumentState.Archived:
statusWMLabel = plugin.string.Archived
break
case DocumentState.Obsolete:
statusWMLabel = plugin.string.Obsolete
break
}
}
@@ -51,7 +54,7 @@
$controlledDocument != null &&
(isOrgSpace
? $controlledDocument.state !== DocumentState.Effective
: ![DocumentState.Effective, DocumentState.Archived].includes($controlledDocument.state))
: ![DocumentState.Effective, DocumentState.Obsolete, DocumentState.Archived].includes($controlledDocument.state))
</script>
{#if $controlledDocument !== null}
@@ -182,6 +182,24 @@ async function archiveDocuments (obj: Document | Document[]): Promise<void> {
})
}
async function makeDocumentObsolete (obj: Document | Document[]): Promise<void> {
const docs = Array.isArray(obj) ? obj : [obj]
const docNames = docs.map((d) => `${d.title} (${d.prefix}-${d.seqNumber})`).join(', ')
showPopup(MessageBox, {
label: documents.string.MakeDocumentObsoleteDialog,
labelProps: { count: docs.length },
message: documents.string.MakeDocumentObsoleteConfirm,
params: { titles: docNames },
action: async () => {
const client = getClient()
for (const doc of docs) {
await client.update(doc, { state: DocumentState.Obsolete })
}
}
})
}
async function canDeleteDocument (obj?: Doc | Doc[]): Promise<boolean> {
if (obj == null) {
return false
@@ -220,6 +238,28 @@ async function canArchiveDocument (obj?: Doc | Doc[]): Promise<boolean> {
).then((res) => res.every((r) => r))
}
async function canMakeDocumentObsolete (obj?: Doc | Doc[]): Promise<boolean> {
if (obj == null) {
return false
}
const objs = (Array.isArray(obj) ? obj : [obj]) as Document[]
const currentUser = getCurrentAccount() as PersonAccount
const isOwner = objs.every((doc) => doc.owner === currentUser.person)
if (isOwner) {
return true
}
const spaces = new Set(objs.map((doc) => doc.space))
return await Promise.all(
Array.from(spaces).map(
async (space) => await checkPermission(getClient(), documents.permission.ArchiveDocument, space)
)
).then((res) => res.every((r) => r))
}
async function canOpenDocument (obj?: ProjectDocument | ProjectDocument[]): Promise<boolean> {
if (obj == null) {
return false
@@ -411,6 +451,7 @@ export default async (): Promise<Resources> => ({
GetDocumentMetaLinkFragment: getDocumentMetaLinkFragment,
CanDeleteDocument: canDeleteDocument,
CanArchiveDocument: canArchiveDocument,
CanMakeDocumentObsolete: canMakeDocumentObsolete,
CanTransferDocument: canTransferDocument,
CanOpenDocument: canOpenDocument,
CanPrintDocument: canPrintDocument,
@@ -430,6 +471,7 @@ export default async (): Promise<Resources> => ({
CreateFolder: createFolder,
DeleteDocument: deleteDocuments,
ArchiveDocument: archiveDocuments,
MakeDocumentObsolete: makeDocumentObsolete,
TransferDocument: transferDocuments,
EditDocSpace: editDocSpace
},
@@ -242,6 +242,7 @@ export default mergeIds(documentsId, documents, {
GetDocumentMetaLinkFragment: '' as Resource<(doc: Doc, props: Record<string, any>) => Promise<Location>>,
CanDeleteDocument: '' as Resource<(doc?: Doc | Doc[]) => Promise<boolean>>,
CanArchiveDocument: '' as Resource<(doc?: Doc | Doc[]) => Promise<boolean>>,
CanMakeDocumentObsolete: '' as Resource<(doc?: Doc | Doc[]) => Promise<boolean>>,
CanOpenDocument: '' as Resource<(doc?: Doc | Doc[]) => Promise<boolean>>,
CanPrintDocument: '' as Resource<(doc?: Doc | Doc[]) => Promise<boolean>>,
CanTransferDocument: '' as Resource<(doc?: Doc | Doc[]) => Promise<boolean>>,
@@ -21,9 +21,10 @@ export const $canCreateNewDraft = combine($controlledDocument, $documentAllVersi
if (document == null) return false
const currentIndex = versions.findIndex((p) => p._id === document._id)
const forbiddenStates = [DocumentState.Draft, DocumentState.Obsolete]
return (
versions.slice(0, currentIndex).every((p) => p.state === DocumentState.Deleted) &&
document.state !== DocumentState.Draft
!forbiddenStates.includes(document.state)
)
})
@@ -82,7 +82,8 @@ export async function getTranslatedDocumentStates (lang: string): Promise<Transl
[DocumentState.Draft]: await translate(documents.string.Draft, {}, lang),
[DocumentState.Deleted]: await translate(documents.string.Deleted, {}, lang),
[DocumentState.Effective]: await translate(documents.string.Effective, {}, lang),
[DocumentState.Archived]: await translate(documents.string.Archived, {}, lang)
[DocumentState.Archived]: await translate(documents.string.Archived, {}, lang),
[DocumentState.Obsolete]: await translate(documents.string.Obsolete, {}, lang)
}
}
@@ -159,6 +160,8 @@ export async function getDocumentMetaLinkFragment (document: Doc): Promise<Locat
break
} else if (doc.state === DocumentState.Deleted && targetDocument === undefined) {
targetDocument = doc
} else if (doc.state === DocumentState.Obsolete && targetDocument === undefined) {
targetDocument = doc
} else if (doc.state === DocumentState.Draft) {
targetDocument = doc
} else if (doc.state === DocumentState.Archived) {
@@ -363,13 +366,15 @@ export const statesTags: StatesTags = {
[DocumentState.Draft]: 'draft',
[DocumentState.Effective]: 'effective',
[DocumentState.Archived]: 'obsolete',
[DocumentState.Deleted]: 'obsolete'
[DocumentState.Deleted]: 'obsolete',
[DocumentState.Obsolete]: 'obsolete'
}
export const documentStatesOrder = [
DocumentState.Draft,
DocumentState.Effective,
DocumentState.Archived,
DocumentState.Obsolete,
DocumentState.Deleted
]
@@ -121,6 +121,7 @@ export const documentsPlugin = plugin(documentsId, {
DeleteDocumentCategory: '' as Ref<Action<Doc, any>>,
DeleteDocument: '' as Ref<Action>,
ArchiveDocument: '' as Ref<Action>,
MakeDocumentObsolete: '' as Ref<Action>,
EditDocSpace: '' as Ref<Action>,
TransferDocument: '' as Ref<Action>,
Print: '' as Ref<Action<Doc, { signed: boolean }>>,
@@ -202,6 +203,10 @@ export const documentsPlugin = plugin(documentsId, {
Deleted: '' as IntlString,
Effective: '' as IntlString,
Archived: '' as IntlString,
Obsolete: '' as IntlString,
MakeDocumentObsolete: '' as IntlString,
MakeDocumentObsoleteDialog: '' as IntlString,
MakeDocumentObsoleteConfirm: '' as IntlString,
Parent: '' as IntlString,
Template: '' as IntlString,
GeneralInfo: '' as IntlString,
+2 -1
View File
@@ -194,7 +194,8 @@ export enum DocumentState {
Draft = 'draft',
Effective = 'effective',
Archived = 'archived',
Deleted = 'deleted'
Deleted = 'deleted',
Obsolete = 'obsolete'
}
/**