Merge branch 'master' into feat/external-apis

This commit is contained in:
Sarah Vaupel 2022-06-04 00:43:31 +02:00
commit 0c4890cbde
31 changed files with 1794 additions and 1441 deletions

View File

@ -299,3 +299,5 @@ bot-mitigations:
volatile-cluster-settings-cache-time: 10
communication-attachments-max-size: 20971520 # 20MiB
workflow-workflow-archive-after: 5270400 # 61 days

View File

@ -60,7 +60,6 @@ export class AsyncForm {
setTimeout(() => {
parentElement.insertBefore(responseElement, this._element);
this._element.remove();
this._app.utilRegistry.destroyAll(this._element);
}, delay);
}

View File

@ -447,7 +447,6 @@ export class AsyncTable {
this._element.classList.remove(ASYNC_TABLE_INITIALIZED_CLASS);
this._element.dataset['currentTableUrl'] = url.href;
this._app.utilRegistry.destroyAll(this._element);
// update table with new
this._element.innerHTML = response.element.innerHTML;

View File

@ -106,6 +106,8 @@ WorkflowWorkflowWorkflowStateHeading: Zustand/Daten
WorkflowWorkflowWorkflowPayloadHeading: Aktueller Datensatz
WorkflowWorkflowWorkflowStateStateLabel: Aktueller Zustand
WorkflowWorkflowWorkflowStateStateHidden: Versteckter Zustand
WorkflowWorkflowWorkflowStateArchivedLabel: Archiviert seit
WorkflowWorkflowWorkflowArchivationInfo: Workflows, welche seit 61 Tagen abgeschlossen sind, werden automatisch archiviert. Aktionen setzen den Archivierungszeitpunkt eines Workflows zurück.
WorkflowWorkflowWorkflowHistoryLabelOthers: Aktionen Anderer
WorkflowWorkflowWorkflowHistoryLabelOwn: Eigene Aktionen
@ -123,18 +125,18 @@ GlobalWorkflowWorkflowWorkflowTitle workflowWorkflowId@CryptoFileNameWorkflowWor
SchoolWorkflowWorkflowWorkflowHeading ssh@SchoolId workflowWorkflowId@CryptoFileNameWorkflowWorkflow !ident-ok: Workflow #{ssh}, #{toPathPiece workflowWorkflowId}
SchoolWorkflowWorkflowWorkflowTitle ssh@SchoolId workflowWorkflowId@CryptoFileNameWorkflowWorkflow !ident-ok: Workflow #{ssh}, #{toPathPiece workflowWorkflowId}
WorkflowWorkflowListScopeTitle rScope@RouteWorkflowScope: Laufende Workflows - _{rScope}
WorkflowWorkflowListScopeHeading rScope@RouteWorkflowScope: Laufende Workflows (_{rScope})
WorkflowWorkflowListInstanceTitle: Laufende Workflows für Instanz
WorkflowWorkflowListInstanceHeading: Laufende Workflows für Instanz
WorkflowWorkflowListNamedInstanceTitle rScope@RouteWorkflowScope wiTitle@Text: Laufende Workflows - _{rScope}, #{wiTitle}
WorkflowWorkflowListNamedInstanceHeading rScope@RouteWorkflowScope wiTitle@Text: Laufende Workflows (_{rScope}, #{wiTitle})
WorkflowWorkflowListNamedInstanceTitleDisabled rScope@RouteWorkflowScope: Laufende Workflows - _{rScope}
WorkflowWorkflowListNamedInstanceHeadingDisabled rScope@RouteWorkflowScope: Laufende Workflows (_{rScope})
WorkflowWorkflowListTopTitle: Laufende Workflows
WorkflowWorkflowListTopHeading: Laufende Workflows
AdminWorkflowWorkflowListTitle: Laufende Workflows
AdminWorkflowWorkflowListHeading: Laufende Workflows
WorkflowWorkflowListScopeTitle rScope@RouteWorkflowScope listType@WorkflowWorkflowListType !ident-ok: _{listType} - _{rScope}
WorkflowWorkflowListScopeHeading rScope@RouteWorkflowScope listType@WorkflowWorkflowListType !ident-ok: _{listType} (_{rScope})
WorkflowWorkflowListInstanceTitle listType@WorkflowWorkflowListType: _{listType} für Instanz
WorkflowWorkflowListInstanceHeading listType@WorkflowWorkflowListType: _{listType} für Instanz
WorkflowWorkflowListNamedInstanceTitle rScope@RouteWorkflowScope wiTitle@Text listType@WorkflowWorkflowListType !ident-ok: _{listType} - _{rScope}, #{wiTitle}
WorkflowWorkflowListNamedInstanceHeading rScope@RouteWorkflowScope wiTitle@Text listType@WorkflowWorkflowListType !ident-ok: _{listType} (_{rScope}, #{wiTitle})
WorkflowWorkflowListNamedInstanceTitleDisabled rScope@RouteWorkflowScope listType@WorkflowWorkflowListType !ident-ok: _{listType} - _{rScope}
WorkflowWorkflowListNamedInstanceHeadingDisabled rScope@RouteWorkflowScope listType@WorkflowWorkflowListType !ident-ok: _{listType} _{rScope})
WorkflowWorkflowListTopTitle listType@WorkflowWorkflowListType !ident-ok: _{listType}
WorkflowWorkflowListTopHeading listType@WorkflowWorkflowListType !ident-ok: _{listType}
AdminWorkflowWorkflowListTitle: Alle Workflows
AdminWorkflowWorkflowListHeading: Alle Workflows
WorkflowWorkflowListNumber: Nummer
WorkflowWorkflowListScope: Bereich
@ -144,6 +146,10 @@ WorkflowWorkflowListLastActionTime: Zeitpunkt, letzte Aktion
WorkflowWorkflowListLastActionUser: Benutzer:in, letzte Aktion
WorkflowWorkflowListIsFinal: Abgeschlossen?
WorkflowWorkflowListActive: Laufende Workflows
WorkflowWorkflowListArchive: Archivierte Workflows
WorkflowWorkflowListAll: Alle Workflows
WorkflowGraphFormUploadIsDirectory: Upload ist Verzeichnis
WorkflowGraphFormInvalidNumberOfFiles: Es muss genau eine Datei hochgeladen werden
WorkflowCourseOption tid@TermId ssh@SchoolId coursen@CourseName !ident-ok: #{tid} - #{ssh} - #{coursen}
@ -160,4 +166,4 @@ WorkflowInstanceUpdateUpdatedCategory: Kategorie-Update erfolgreich angewandt
WorkflowInstanceUpdateDeletedDescriptionLanguage lang@Lang: Beschreibung/Titel in Sprache „#{lang}“ gelöscht
WorkflowInstanceUpdateUpdatedDescriptionLanguage lang@Lang: Beschreibung/Titel-Update für Sprache „#{lang}“ angewandt
WorkflowsDisabled: Workflows sind temporär deaktiviert.
WorkflowsDisabled: Workflows sind zur Zeit deaktiviert.

View File

@ -65,6 +65,8 @@ WorkflowWorkflowWorkflowStateHeading: State/Data
WorkflowWorkflowWorkflowPayloadHeading: Current data
WorkflowWorkflowWorkflowStateStateLabel: Current state
WorkflowWorkflowWorkflowStateStateHidden: Hidden state
WorkflowWorkflowWorkflowStateArchivedLabel: Archived since
WorkflowWorkflowWorkflowArchivationInfo: Workflows that are finalized for 61 days will be automatically moved to the archive. Actions reset the archivation date of a workflow.
WorkflowWorkflowWorkflowHistoryLabelOthers: Other users' actions
WorkflowWorkflowWorkflowHistoryLabelOwn: Your actions
@ -82,18 +84,18 @@ GlobalWorkflowWorkflowWorkflowTitle workflowWorkflowId: Workflow #{toPathPiece w
SchoolWorkflowWorkflowWorkflowHeading ssh workflowWorkflowId: Workflow #{ssh}, #{toPathPiece workflowWorkflowId}
SchoolWorkflowWorkflowWorkflowTitle ssh workflowWorkflowId: Workflow #{ssh}, #{toPathPiece workflowWorkflowId}
WorkflowWorkflowListScopeTitle rScope: Running workflows - _{rScope}
WorkflowWorkflowListScopeHeading rScope: Running workflows (_{rScope})
WorkflowWorkflowListInstanceTitle: Running workflows for an instance
WorkflowWorkflowListInstanceHeading: Running workflows for an instance
WorkflowWorkflowListNamedInstanceTitle rScope wiTitle: Running workflows - _{rScope}, #{wiTitle}
WorkflowWorkflowListNamedInstanceHeading rScope wiTitle: Running workflows (_{rScope}, #{wiTitle})
WorkflowWorkflowListNamedInstanceTitleDisabled rScope: Running Workflows - _{rScope}
WorkflowWorkflowListNamedInstanceHeadingDisabled rScope: Running Workflows (_{rScope})
WorkflowWorkflowListTopTitle: Running workflows
WorkflowWorkflowListTopHeading: Running workflows
AdminWorkflowWorkflowListTitle: Running workflows
AdminWorkflowWorkflowListHeading: Running workflows
WorkflowWorkflowListScopeTitle rScope listType: _{listType} - _{rScope}
WorkflowWorkflowListScopeHeading rScope listType: _{listType} (_{rScope})
WorkflowWorkflowListInstanceTitle listType: _{listType} for an instance
WorkflowWorkflowListInstanceHeading listType: _{listType} for an instance
WorkflowWorkflowListNamedInstanceTitle rScope wiTitle listType: _{listType} - _{rScope}, #{wiTitle}
WorkflowWorkflowListNamedInstanceHeading rScope wiTitle listType: _{listType} (_{rScope}, #{wiTitle})
WorkflowWorkflowListNamedInstanceTitleDisabled rScope listType: _{listType} - _{rScope}
WorkflowWorkflowListNamedInstanceHeadingDisabled rScope listType: _{listType} (_{rScope})
WorkflowWorkflowListTopTitle listType: _{listType}
WorkflowWorkflowListTopHeading listType: _{listType}
AdminWorkflowWorkflowListTitle: All workflows
AdminWorkflowWorkflowListHeading: All workflows
WorkflowWorkflowListNumber: Number
WorkflowWorkflowListScope: Scope
@ -103,6 +105,10 @@ WorkflowWorkflowListLastActionTime: Timestamp of last action
WorkflowWorkflowListLastActionUser: User for last action
WorkflowWorkflowListIsFinal: Finalised?
WorkflowWorkflowListActive: Running workflows
WorkflowWorkflowListArchive: Archived workflows
WorkflowWorkflowListAll: All workflows
WorkflowDefinitionGraph: Specification
WorkflowDefinitionKeyDoesNotExist renderedCryptoID: Referenced id does not exist: #{renderedCryptoID}
WorkflowDefinitionFiles: Files
@ -160,4 +166,4 @@ WorkflowInstanceUpdateUpdatedCategory: Successfully applied updated category
WorkflowInstanceUpdateDeletedDescriptionLanguage lang: Successfully deleted description/title for language “#{lang}”
WorkflowInstanceUpdateUpdatedDescriptionLanguage lang: Successfully applied updated description/title for language “#{lang}”
WorkflowsDisabled: Workflows are temporarily disabled.
WorkflowsDisabled: Workflows are currently disabled.

View File

@ -92,19 +92,19 @@ BreadcrumbAdminWorkflowWorkflowList: Initiierte Workflows
BreadcrumbAdminWorkflowWorkflowNew: Workflow initiieren
BreadcrumbWorkflowInstanceEdit win@WorkflowInstanceName !ident-ok: #{win}
BreadcrumbWorkflowInstanceDelete: Löschen
BreadcrumbWorkflowInstanceWorkflowList: Laufende Workflows
BreadcrumbWorkflowInstanceWorkflowList listType@WorkflowWorkflowListType !ident-ok: _{listType}
BreadcrumbWorkflowInstanceInitiate: Workflow starten
BreadcrumbWorkflowInstanceList !ident-ok: Workflows
BreadcrumbWorkflowInstanceNew: Neuer Workflow
BreadcrumbWorkflowInstanceUpdate !ident-ok: Update
BreadcrumbWorkflowWorkflowList: Laufende Workflows
BreadcrumbWorkflowWorkflowList listType@WorkflowWorkflowListType !ident-ok: _{listType}
BreadcrumbWorkflowWorkflow workflow@CryptoFileNameWorkflowWorkflow !ident-ok: #{toPathPiece workflow}
BreadcrumbWorkflowWorkflowFiles: Dateien
BreadcrumbWorkflowWorkflowEdit: Editieren
BreadcrumbWorkflowWorkflowDelete: Löschen
BreadcrumbGlobalWorkflowInstanceList: Systemweite Workflows
BreadcrumbTopWorkflowInstanceList !ident-ok: Workflows
BreadcrumbTopWorkflowWorkflowList: Laufende Workflows
BreadcrumbTopWorkflowWorkflowList listType@WorkflowWorkflowListType !ident-ok: _{listType}
BreadcrumbError: Fehler
BreadcrumbUpload !ident-ok: Upload
BreadcrumbUserAdd: Benutzer:in anlegen

View File

@ -92,19 +92,19 @@ BreadcrumbAdminWorkflowWorkflowList: Initiated workflows
BreadcrumbAdminWorkflowWorkflowNew: Initiate workflow
BreadcrumbWorkflowInstanceEdit win: #{win}
BreadcrumbWorkflowInstanceDelete: Delete
BreadcrumbWorkflowInstanceWorkflowList: Running workflows
BreadcrumbWorkflowInstanceWorkflowList listType: _{listType}
BreadcrumbWorkflowInstanceInitiate: Start workflow
BreadcrumbWorkflowInstanceList: Workflows
BreadcrumbWorkflowInstanceNew: New workflow
BreadcrumbWorkflowInstanceUpdate !ident-ok: Update
BreadcrumbWorkflowWorkflowList: Running workflows
BreadcrumbWorkflowWorkflowList listType: _{listType}
BreadcrumbWorkflowWorkflow workflow: #{toPathPiece workflow}
BreadcrumbWorkflowWorkflowFiles: Files
BreadcrumbWorkflowWorkflowEdit: Edit
BreadcrumbWorkflowWorkflowDelete: Delete
BreadcrumbGlobalWorkflowInstanceList: System-wide workflows
BreadcrumbTopWorkflowInstanceList: Workflows
BreadcrumbTopWorkflowWorkflowList: Running workflows
BreadcrumbTopWorkflowWorkflowList listType: _{listType}
BreadcrumbError: Error
BreadcrumbUpload: Upload
BreadcrumbUserAdd: Add user

View File

@ -126,12 +126,12 @@ MenuWorkflowInstanceDelete: Löschen
MenuWorkflowInstanceWorkflows: Laufende Workflows
MenuWorkflowInstanceInitiate: Workflow starten
MenuWorkflowInstanceEdit: Bearbeiten
MenuWorkflowWorkflowList: Laufende Workflows
MenuWorkflowWorkflowList listType@WorkflowWorkflowListType !ident-ok: _{listType}
MenuWorkflowWorkflowEdit: Editieren
MenuWorkflowWorkflowDelete: Löschen
MenuGlobalWorkflowInstanceList: Systemweite Workflows
MenuTopWorkflowInstanceList !ident-ok: Workflows
MenuTopWorkflowWorkflowList: Laufende Workflows
MenuTopWorkflowWorkflowList listType@WorkflowWorkflowListType !ident-ok: _{listType}
MenuTopWorkflowWorkflowListHeader !ident-ok: Workflows
MenuGlossary: Begriffsverzeichnis
MenuVersion: Versionsgeschichte

View File

@ -127,12 +127,12 @@ MenuWorkflowInstanceDelete: Delete
MenuWorkflowInstanceWorkflows: Running workflows
MenuWorkflowInstanceInitiate: Start workflow
MenuWorkflowInstanceEdit: Edit
MenuWorkflowWorkflowList: Running workflows
MenuWorkflowWorkflowList listType: _{listType}
MenuWorkflowWorkflowEdit: Edit
MenuWorkflowWorkflowDelete: Delete
MenuGlobalWorkflowInstanceList: System-wide workflows
MenuTopWorkflowInstanceList: Workflows
MenuTopWorkflowWorkflowList: Running workflows
MenuTopWorkflowWorkflowList listType: _{listType}
MenuTopWorkflowWorkflowListHeader: Workflows
MenuGlossary: Glossary
MenuVersion: Version history

View File

@ -50,4 +50,5 @@ WorkflowWorkflow
scope (WorkflowScope TermIdentifier SchoolShorthand SqlBackendKey) -- TermId, SchoolId, CourseId
graph SharedWorkflowGraphId
state (WorkflowState FileReference SqlBackendKey) -- UserId
archived UTCTime Maybe
deriving Generic

2689
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -44,19 +44,19 @@
"defaults"
],
"devDependencies": {
"@babel/cli": "^7.17.6",
"@babel/core": "^7.17.9",
"@babel/eslint-parser": "^7.17.0",
"@babel/plugin-proposal-class-properties": "^7.16.7",
"@babel/plugin-proposal-decorators": "^7.17.9",
"@babel/plugin-proposal-private-property-in-object": "^7.16.7",
"@babel/plugin-transform-modules-commonjs": "^7.17.9",
"@babel/plugin-transform-runtime": "^7.17.0",
"@babel/preset-env": "^7.16.11",
"@commitlint/cli": "^16.2.3",
"@commitlint/config-conventional": "^16.2.1",
"@babel/cli": "^7.17.10",
"@babel/core": "^7.18.2",
"@babel/eslint-parser": "^7.18.2",
"@babel/plugin-proposal-class-properties": "^7.17.12",
"@babel/plugin-proposal-decorators": "^7.18.2",
"@babel/plugin-proposal-private-property-in-object": "^7.17.12",
"@babel/plugin-transform-modules-commonjs": "^7.18.2",
"@babel/plugin-transform-runtime": "^7.18.2",
"@babel/preset-env": "^7.18.2",
"@commitlint/cli": "^17.0.1",
"@commitlint/config-conventional": "^17.0.0",
"@fortawesome/fontawesome-pro": "^6.1.1",
"autoprefixer": "^10.4.4",
"autoprefixer": "^10.4.7",
"babel-core": "^6.26.3",
"babel-loader": "^8.2.5",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
@ -65,40 +65,40 @@
"babel-preset-es2015": "^6.24.1",
"changelog-parser": "^2.8.1",
"clean-webpack-plugin": "^4.0.0",
"copy-webpack-plugin": "^10.2.4",
"copy-webpack-plugin": "^11.0.0",
"css-loader": "^6.7.1",
"eslint": "^8.13.0",
"eslint": "^8.16.0",
"file-loader": "^6.2.0",
"fs-extra": "^10.1.0",
"glob": "^8.0.1",
"glob": "^8.0.3",
"html-webpack-plugin": "^5.5.0",
"husky": "^7.0.4",
"jasmine-core": "^4.1.0",
"husky": "^8.0.1",
"jasmine-core": "^4.1.1",
"js-yaml": "^4.1.0",
"karma": "^6.3.19",
"karma": "^6.3.20",
"karma-chrome-launcher": "^3.1.1",
"karma-cli": "^2.0.0",
"karma-jasmine": "^5.0.0",
"karma-jasmine-html-reporter": "^1.7.0",
"karma-jasmine": "^5.0.1",
"karma-jasmine-html-reporter": "^2.0.0",
"karma-mocha-reporter": "^2.2.5",
"karma-webpack": "^5.0.0",
"lint-staged": "^12.4.0",
"lint-staged": "^12.4.2",
"lodash.debounce": "^4.0.8",
"mini-css-extract-plugin": "^2.6.0",
"npm-run-all": "^4.1.5",
"null-loader": "^4.0.1",
"optimize-css-assets-webpack-plugin": "^6.0.1",
"postcss-loader": "^6.2.1",
"postcss-preset-env": "^7.4.3",
"postcss-loader": "^7.0.0",
"postcss-preset-env": "^7.6.0",
"real-favicon-webpack-plugin": "^0.2.3",
"remove-files-webpack-plugin": "^1.5.0",
"request": "^2.88.2",
"request-promise": "^4.2.6",
"resolve-url-loader": "^5.0.0",
"sass": "^1.50.1",
"sass-loader": "^12.6.0",
"sass": "^1.52.1",
"sass-loader": "^13.0.0",
"semver": "^7.3.7",
"standard-version": "^9.3.2",
"standard-version": "^9.5.0",
"standard-version-updater-yaml": "^1.0.3",
"style-loader": "^3.3.1",
"terser-webpack-plugin": "^5.3.1",
@ -106,22 +106,22 @@
"typeface-roboto": "1.1.13",
"typeface-source-code-pro": "^1.1.13",
"typeface-source-sans-pro": "1.1.13",
"webpack": "^5.72.0",
"webpack": "^5.72.1",
"webpack-cli": "^4.9.2",
"webpack-manifest-plugin": "^5.0.0"
},
"dependencies": {
"@babel/runtime": "^7.17.9",
"@babel/runtime": "^7.18.3",
"@juggle/resize-observer": "^3.3.1",
"core-js": "^3.22.2",
"core-js": "^3.22.7",
"css.escape": "^1.5.1",
"js-cookie": "^3.0.1",
"lodash.debounce": "^4.0.8",
"lodash.defer": "^4.1.0",
"lodash.throttle": "^4.1.1",
"moment": "^2.29.3",
"npm": "^8.7.0",
"npm-check-updates": "^12.5.9",
"npm": "^8.11.0",
"npm-check-updates": "^13.0.3",
"sodium-javascript": "^0.8.0",
"toposort": "^2.0.2",
"whatwg-fetch": "^3.6.2"

28
routes
View File

@ -76,20 +76,20 @@
/global-workflows/instances GlobalWorkflowInstanceListR GET !free
/global-workflows/instances/new GlobalWorkflowInstanceNewR GET POST
/global-workflows/instances/#WorkflowInstanceName GlobalWorkflowInstanceR:
/edit GWIEditR GET POST
/delete GWIDeleteR GET POST
/workflows GWIWorkflowsR GET !free
/initiate GWIInitiateR GET POST !workflow
/update GWIUpdateR POST
/global-workflows GlobalWorkflowWorkflowListR GET !free
/edit GWIEditR GET POST
/delete GWIDeleteR GET POST
/workflows/#WorkflowWorkflowListType GWIWorkflowsR GET !free
/initiate GWIInitiateR GET POST !workflow
/update GWIUpdateR POST
!/global-workflows/#WorkflowWorkflowListType GlobalWorkflowWorkflowListR GET !free
!/global-workflows/#CryptoFileNameWorkflowWorkflow GlobalWorkflowWorkflowR:
/ GWWWorkflowR GET POST !workflow
/files/#WorkflowPayloadLabel/#CryptoUUIDWorkflowStateIndex GWWFilesR GET !workflow
/edit GWWEditR GET POST
/delete GWWDeleteR GET POST
/workflow-instances TopWorkflowInstanceListR GET !free
/workflows TopWorkflowWorkflowListR GET !free
/workflow-instances TopWorkflowInstanceListR GET !free
/workflows/#WorkflowWorkflowListType TopWorkflowWorkflowListR GET !free
/health HealthR GET !free
/instance InstanceR GET !free
@ -145,12 +145,12 @@
/workflows/instances SchoolWorkflowInstanceListR GET !free
/workflows/instances/new SchoolWorkflowInstanceNewR GET POST
/workflows/instances/#WorkflowInstanceName SchoolWorkflowInstanceR:
/edit SWIEditR GET POST
/delete SWIDeleteR GET POST
/workflows SWIWorkflowsR GET !free
/initiate SWIInitiateR GET POST !workflow
/update SWIUpdateR POST
/workflows SchoolWorkflowWorkflowListR GET !free
/edit SWIEditR GET POST
/delete SWIDeleteR GET POST
/workflows/#WorkflowWorkflowListType SWIWorkflowsR GET !free
/initiate SWIInitiateR GET POST !workflow
/update SWIUpdateR POST
!/workflows/#WorkflowWorkflowListType SchoolWorkflowWorkflowListR GET !free
!/workflows/#CryptoFileNameWorkflowWorkflow SchoolWorkflowWorkflowR:
/ SWWWorkflowR GET POST !workflow
/files/#WorkflowPayloadLabel/#CryptoUUIDWorkflowStateIndex SWWFilesR GET !workflow

View File

@ -1574,7 +1574,7 @@ tagAccessPredicate AuthEmpty = APDB $ \evalCtx eval' mAuthId route _ -> do
orAR' = shortCircuitM (is _Authorized) (orAR mr)
_andAR' = shortCircuitM (is _Unauthorized) (andAR mr)
workflowInstanceWorkflowsEmpty rScope win = workflowsEnabledAuth $ selectLanguageI18n <=< $cachedHereBinary (evalCtx, mAuthId, route) . maybeT (unauthorizedI18n MsgUnauthorizedWorkflowWorkflowsNotEmpty) $ do
workflowInstanceWorkflowsEmpty rScope win _lState = workflowsEnabledAuth $ selectLanguageI18n <=< $cachedHereBinary (evalCtx, mAuthId, route) . maybeT (unauthorizedI18n MsgUnauthorizedWorkflowWorkflowsNotEmpty) $ do
roles <- memcacheAuth' (Right diffDay) (AuthCacheWorkflowInstanceWorkflowViewers win rScope) $ do
scope <- fromRouteWorkflowScope rScope
let dbScope = scope ^. _DBWorkflowScope
@ -1609,8 +1609,8 @@ tagAccessPredicate AuthEmpty = APDB $ \evalCtx eval' mAuthId route _ -> do
guardM . fmap (isn't _Authorized) $ ofoldl1' orAR' . mapNonNull evalRole =<< hoistMaybe (fromNullable $ otoList roles)
return AuthorizedI18n
in case route of
r | Just (rScope, WorkflowInstanceR win WIWorkflowsR) <- r ^? _WorkflowScopeRoute
-> workflowInstanceWorkflowsEmpty rScope win
r | Just (rScope, WorkflowInstanceR win (WIWorkflowsR lState)) <- r ^? _WorkflowScopeRoute
-> workflowInstanceWorkflowsEmpty rScope win lState
EExamListR -> exceptT return return $ do
authId <- maybeExceptT AuthenticationRequired $ return mAuthId
hasExternalExams <- $cachedHereBinary authId . lift . E.selectExists . E.from $ \(eexam `E.InnerJoin` eexamStaff) -> do

View File

@ -514,6 +514,8 @@ instance RenderMessage UniWorX RouteWorkflowScope where
mr :: forall msg. RenderMessage UniWorX msg => msg -> Text
mr = renderMessage foundation ls
embedRenderMessage ''UniWorX ''WorkflowWorkflowListType id
instance RenderMessage UniWorX VolatileClusterSettingsKey where
renderMessage foundation ls = \case
ClusterVolatileWorkflowsEnabled -> mr MsgClusterVolatileWorkflowsEnabled

View File

@ -118,7 +118,7 @@ breadcrumb AdminTokensR = i18nCrumb MsgMenuAdminTokens $ Just AdminR
breadcrumb AdminCrontabR = i18nCrumb MsgBreadcrumbAdminCrontab $ Just AdminR
breadcrumb SchoolListR = i18nCrumb MsgMenuSchoolList $ Just AdminR
breadcrumb (SchoolR ssh sRoute) = case sRoute of
breadcrumb currentRoute@(SchoolR ssh sRoute) = case sRoute of
SchoolEditR -> useRunDB . maybeT (i18nCrumb MsgBreadcrumbSchool $ Just SchoolListR) $ do
School{..} <- MaybeT $ get ssh
isAdmin <- lift $ hasReadAccessTo SchoolListR
@ -129,7 +129,7 @@ breadcrumb (SchoolR ssh sRoute) = case sRoute of
SchoolWorkflowInstanceR win sRoute' -> case sRoute' of
SWIEditR -> do
desc <- useRunDB . runMaybeT $ do
guardM . lift . hasReadAccessTo . SchoolR ssh $ SchoolWorkflowInstanceR win SWIWorkflowsR
guardM . lift . hasReadAccessTo . SchoolR ssh . SchoolWorkflowInstanceR win $ SWIWorkflowsR WorkflowWorkflowListActive
wiId <- MaybeT . getKeyBy . UniqueWorkflowInstance win . WSSchool $ unSchoolKey ssh
MaybeT $ selectWorkflowInstanceDescription wiId
let bRoute = SchoolR ssh SchoolWorkflowInstanceListR
@ -137,16 +137,24 @@ breadcrumb (SchoolR ssh sRoute) = case sRoute of
Nothing -> i18nCrumb (MsgBreadcrumbWorkflowInstanceEdit win) $ Just bRoute
Just (Entity _ WorkflowInstanceDescription{..}) -> i18nCrumb workflowInstanceDescriptionTitle $ Just bRoute
SWIDeleteR -> i18nCrumb MsgBreadcrumbWorkflowInstanceDelete . Just . SchoolR ssh $ SchoolWorkflowInstanceR win SWIEditR
SWIWorkflowsR -> i18nCrumb MsgBreadcrumbWorkflowInstanceWorkflowList . Just . SchoolR ssh $ SchoolWorkflowInstanceR win SWIEditR
SWIWorkflowsR lState -> i18nCrumb (MsgBreadcrumbWorkflowInstanceWorkflowList lState) . Just . SchoolR ssh $ SchoolWorkflowInstanceR win SWIEditR
SWIInitiateR -> useRunDB $ do
mayEdit <- hasReadAccessTo . SchoolR ssh $ SchoolWorkflowInstanceR win SWIEditR
i18nCrumb MsgBreadcrumbWorkflowInstanceInitiate . Just . SchoolR ssh $ if
| mayEdit -> SchoolWorkflowInstanceR win SWIEditR
| otherwise -> SchoolWorkflowInstanceListR
SWIUpdateR -> i18nCrumb MsgBreadcrumbWorkflowInstanceUpdate . Just . SchoolR ssh $ SchoolWorkflowInstanceR win SWIEditR
SchoolWorkflowWorkflowListR -> i18nCrumb MsgBreadcrumbWorkflowWorkflowList . Just $ SchoolR ssh SchoolWorkflowInstanceListR
SchoolWorkflowWorkflowListR lState -> i18nCrumb (MsgBreadcrumbWorkflowWorkflowList lState) . Just $ SchoolR ssh SchoolWorkflowInstanceListR
SchoolWorkflowWorkflowR cID sRoute' -> case sRoute' of
SWWWorkflowR -> i18nCrumb (MsgBreadcrumbWorkflowWorkflow cID) . Just $ SchoolR ssh SchoolWorkflowWorkflowListR
SWWWorkflowR -> do
now <- liftIO getCurrentTime
mWorkflowWorkflow <- useRunDB . runMaybeT $ do
guardM . lift $ hasReadAccessTo currentRoute
wwId <- lift $ decrypt cID
MaybeT $ get wwId
let listType | Just WorkflowWorkflow{workflowWorkflowArchived=Just archived} <- mWorkflowWorkflow, archived <= now = WorkflowWorkflowListArchive
| otherwise = WorkflowWorkflowListActive
i18nCrumb (MsgBreadcrumbWorkflowWorkflow cID) . Just . SchoolR ssh $ SchoolWorkflowWorkflowListR listType
SWWFilesR _ _ -> i18nCrumb MsgBreadcrumbWorkflowWorkflowFiles . Just . SchoolR ssh $ SchoolWorkflowWorkflowR cID SWWWorkflowR
SWWEditR -> i18nCrumb MsgBreadcrumbWorkflowWorkflowEdit . Just . SchoolR ssh $ SchoolWorkflowWorkflowR cID SWWWorkflowR
SWWDeleteR -> i18nCrumb MsgBreadcrumbWorkflowWorkflowDelete . Just . SchoolR ssh $ SchoolWorkflowWorkflowR cID SWWWorkflowR
@ -417,29 +425,37 @@ breadcrumb GlobalWorkflowInstanceNewR = i18nCrumb MsgBreadcrumbWorkflowInstanceN
breadcrumb (GlobalWorkflowInstanceR win sRoute) = case sRoute of
GWIEditR -> do
desc <- useRunDB . runMaybeT $ do
guardM . lift . hasReadAccessTo $ GlobalWorkflowInstanceR win GWIWorkflowsR
guardM . lift . hasReadAccessTo . GlobalWorkflowInstanceR win $ GWIWorkflowsR WorkflowWorkflowListActive
wiId <- MaybeT . getKeyBy $ UniqueWorkflowInstance win WSGlobal
MaybeT $ selectWorkflowInstanceDescription wiId
case desc of
Nothing -> i18nCrumb (MsgBreadcrumbWorkflowInstanceEdit win) $ Just GlobalWorkflowInstanceListR
Just (Entity _ WorkflowInstanceDescription{..}) -> i18nCrumb workflowInstanceDescriptionTitle $ Just GlobalWorkflowInstanceListR
GWIDeleteR -> i18nCrumb MsgBreadcrumbWorkflowInstanceDelete . Just $ GlobalWorkflowInstanceR win GWIEditR
GWIWorkflowsR -> i18nCrumb MsgBreadcrumbWorkflowInstanceWorkflowList . Just $ GlobalWorkflowInstanceR win GWIEditR
GWIWorkflowsR lState -> i18nCrumb (MsgBreadcrumbWorkflowInstanceWorkflowList lState) . Just $ GlobalWorkflowInstanceR win GWIEditR
GWIInitiateR -> do
mayEdit <- useRunDB . hasReadAccessTo $ GlobalWorkflowInstanceR win GWIEditR
i18nCrumb MsgBreadcrumbWorkflowInstanceInitiate . Just $ if
| mayEdit -> GlobalWorkflowInstanceR win GWIEditR
| otherwise -> GlobalWorkflowInstanceListR
GWIUpdateR -> i18nCrumb MsgBreadcrumbWorkflowInstanceUpdate . Just $ GlobalWorkflowInstanceR win GWIEditR
breadcrumb GlobalWorkflowWorkflowListR = i18nCrumb MsgBreadcrumbWorkflowWorkflowList $ Just GlobalWorkflowInstanceListR
breadcrumb (GlobalWorkflowWorkflowR cID sRoute) = case sRoute of
GWWWorkflowR -> i18nCrumb (MsgBreadcrumbWorkflowWorkflow cID) $ Just GlobalWorkflowWorkflowListR
breadcrumb (GlobalWorkflowWorkflowListR lState) = i18nCrumb (MsgBreadcrumbWorkflowWorkflowList lState) $ Just GlobalWorkflowInstanceListR
breadcrumb currentRoute@(GlobalWorkflowWorkflowR cID sRoute) = case sRoute of
GWWWorkflowR -> do
now <- liftIO getCurrentTime
mWorkflowWorkflow <- useRunDB . runMaybeT $ do
guardM . lift $ hasReadAccessTo currentRoute
wwId <- lift $ decrypt cID
MaybeT $ get wwId
let listType | Just WorkflowWorkflow{workflowWorkflowArchived=Just archived} <- mWorkflowWorkflow, archived <= now = WorkflowWorkflowListArchive
| otherwise = WorkflowWorkflowListActive
i18nCrumb (MsgBreadcrumbWorkflowWorkflow cID) . Just $ GlobalWorkflowWorkflowListR listType
GWWFilesR _ _ -> i18nCrumb MsgBreadcrumbWorkflowWorkflowFiles . Just $ GlobalWorkflowWorkflowR cID GWWWorkflowR
GWWEditR -> i18nCrumb MsgBreadcrumbWorkflowWorkflowEdit . Just $ GlobalWorkflowWorkflowR cID GWWWorkflowR
GWWDeleteR -> i18nCrumb MsgBreadcrumbWorkflowWorkflowDelete . Just $ GlobalWorkflowWorkflowR cID GWWWorkflowR
breadcrumb TopWorkflowInstanceListR = i18nCrumb MsgBreadcrumbTopWorkflowInstanceList Nothing
breadcrumb TopWorkflowWorkflowListR = i18nCrumb MsgBreadcrumbTopWorkflowWorkflowList $ Just TopWorkflowInstanceListR
breadcrumb TopWorkflowInstanceListR = i18nCrumb MsgBreadcrumbTopWorkflowInstanceList Nothing
breadcrumb (TopWorkflowWorkflowListR lType) = i18nCrumb (MsgBreadcrumbTopWorkflowWorkflowList lType) $ Just TopWorkflowInstanceListR
breadcrumb (ExternalApisR _) = i18nCrumb MsgBreadcrumbExternalApis Nothing
@ -2601,8 +2617,8 @@ pageActions AdminWorkflowInstanceListR = return
pageActions route | Just (rScope, WorkflowInstanceListR) <- route ^? _WorkflowScopeRoute = return
[ NavPageActionPrimary
{ navLink = NavLink
{ navLabel = MsgMenuWorkflowWorkflowList
, navRoute = _WorkflowScopeRoute # (rScope, WorkflowWorkflowListR)
{ navLabel = MsgMenuWorkflowWorkflowList WorkflowWorkflowListActive
, navRoute = _WorkflowScopeRoute # (rScope, WorkflowWorkflowListR WorkflowWorkflowListActive)
, navAccess' = NavAccessDB $ haveWorkflowWorkflows rScope
, navType = NavTypeLink { navModal = False }
, navQuick' = mempty
@ -2625,7 +2641,7 @@ pageActions route | Just (rScope, WorkflowInstanceR win WIEditR) <- route ^? _Wo
, NavPageActionPrimary
{ navLink = NavLink
{ navLabel = MsgMenuWorkflowInstanceWorkflows
, navRoute = _WorkflowScopeRoute # (rScope, WorkflowInstanceR win WIWorkflowsR)
, navRoute = _WorkflowScopeRoute # (rScope, WorkflowInstanceR win $ WIWorkflowsR WorkflowWorkflowListActive)
, navAccess' = NavAccessTrue
, navType = NavTypeLink { navModal = False }
, navQuick' = mempty
@ -2645,6 +2661,22 @@ pageActions route | Just (rScope, WorkflowInstanceR win WIEditR) <- route ^? _Wo
, navChildren = []
}
]
pageActions route | Just (rScope, WorkflowWorkflowListR lState) <- route ^? _WorkflowScopeRoute =
let lState' | lState == WorkflowWorkflowListActive = WorkflowWorkflowListArchive
| otherwise = WorkflowWorkflowListActive
in return
[ NavPageActionPrimary
{ navLink = NavLink
{ navLabel = MsgMenuWorkflowWorkflowList lState'
, navRoute = _WorkflowScopeRoute # (rScope, WorkflowWorkflowListR lState')
, navAccess' = NavAccessTrue
, navType = NavTypeLink { navModal = False }
, navQuick' = mempty
, navForceActive = False
}
, navChildren = []
}
]
pageActions route | Just (rScope, WorkflowWorkflowR cID WWWorkflowR) <- route ^? _WorkflowScopeRoute = return
[ NavPageActionSecondary
{ navLink = NavLink
@ -2670,8 +2702,8 @@ pageActions route | Just (rScope, WorkflowWorkflowR cID WWWorkflowR) <- route ^?
pageActions TopWorkflowInstanceListR = return
[ NavPageActionPrimary
{ navLink = NavLink
{ navLabel = MsgMenuTopWorkflowWorkflowList
, navRoute = TopWorkflowWorkflowListR
{ navLabel = MsgMenuTopWorkflowWorkflowList WorkflowWorkflowListActive
, navRoute = TopWorkflowWorkflowListR WorkflowWorkflowListActive
, navAccess' = NavAccessDB haveTopWorkflowWorkflows
, navType = NavTypeLink { navModal = False }
, navQuick' = mempty
@ -2693,6 +2725,38 @@ pageActions ApiDocsR = return
, navChildren = []
}
]
pageActions (TopWorkflowWorkflowListR lState) =
let lState' | lState == WorkflowWorkflowListActive = WorkflowWorkflowListArchive
| otherwise = WorkflowWorkflowListActive
in return
[ NavPageActionPrimary
{ navLink = NavLink
{ navLabel = MsgMenuTopWorkflowWorkflowList lState'
, navRoute = TopWorkflowWorkflowListR lState'
, navAccess' = NavAccessTrue
, navType = NavTypeLink { navModal = False }
, navQuick' = mempty
, navForceActive = False
}
, navChildren = []
}
]
pageActions (SchoolR ssh (SchoolWorkflowInstanceR swiName (SWIWorkflowsR lState))) =
let lState' | lState == WorkflowWorkflowListActive = WorkflowWorkflowListArchive
| otherwise = WorkflowWorkflowListActive
in return
[ NavPageActionPrimary
{ navLink = NavLink
{ navLabel = MsgMenuWorkflowWorkflowList lState'
, navRoute = SchoolR ssh . SchoolWorkflowInstanceR swiName $ SWIWorkflowsR lState'
, navAccess' = NavAccessTrue
, navType = NavTypeLink { navModal = False }
, navQuick' = mempty
, navForceActive = False
}
, navChildren = []
}
]
pageActions _ = return []
submissionList :: ( MonadIO m

View File

@ -42,11 +42,13 @@ getLegalR =
-- | Allgemeine Informationen
getInfoR :: Handler Html
getInfoR = do
AppSettings{..} <- getsYesod appSettings'
changelogEntries' <- runDB $ selectList [ ChangelogItemFirstSeenItem <-. universeF ] []
let changelogEntries = Map.fromListWith Set.union
[ (Down changelogItemFirstSeenFirstSeen, Set.singleton changelogItemFirstSeenItem)
| Entity _ ChangelogItemFirstSeen{..} <- changelogEntries'
]
changelogItems = $(i18nWidgetFiles "changelog")
siteLayoutMsg MsgInfoHeading $ do
setTitleI MsgInfoHeading
@ -58,9 +60,6 @@ getInfoR = do
gitInfo = $gitDescribe <> " (" <> $gitCommitDate <> ")"
$(widgetFile "versionHistory")
where
changelogItems = $(i18nWidgetFiles "changelog")
getGlossaryR :: Handler Html
getGlossaryR =

View File

@ -11,12 +11,12 @@ data WorkflowScopeRoute
= WorkflowInstanceListR
| WorkflowInstanceNewR
| WorkflowInstanceR WorkflowInstanceName WorkflowInstanceR
| WorkflowWorkflowListR
| WorkflowWorkflowListR WorkflowWorkflowListType
| WorkflowWorkflowR CryptoFileNameWorkflowWorkflow WorkflowWorkflowR
deriving (Eq, Ord, Read, Show, Generic, Typeable)
data WorkflowInstanceR
= WIEditR | WIDeleteR | WIWorkflowsR | WIInitiateR | WIUpdateR
= WIEditR | WIDeleteR | WIWorkflowsR WorkflowWorkflowListType | WIInitiateR | WIUpdateR
deriving (Eq, Ord, Read, Show, Generic, Typeable)
data WorkflowWorkflowR
@ -32,12 +32,12 @@ _WorkflowScopeRoute = prism' (uncurry toRoute) toWorkflowScopeRoute
WorkflowInstanceListR -> GlobalWorkflowInstanceListR
WorkflowInstanceNewR -> GlobalWorkflowInstanceNewR
WorkflowInstanceR win subRoute -> GlobalWorkflowInstanceR win $ case subRoute of
WIEditR -> GWIEditR
WIDeleteR -> GWIDeleteR
WIWorkflowsR -> GWIWorkflowsR
WIInitiateR -> GWIInitiateR
WIUpdateR -> GWIUpdateR
WorkflowWorkflowListR -> GlobalWorkflowWorkflowListR
WIEditR -> GWIEditR
WIDeleteR -> GWIDeleteR
WIWorkflowsR lState -> GWIWorkflowsR lState
WIInitiateR -> GWIInitiateR
WIUpdateR -> GWIUpdateR
WorkflowWorkflowListR lState -> GlobalWorkflowWorkflowListR lState
WorkflowWorkflowR wwCID subRoute -> GlobalWorkflowWorkflowR wwCID $ case subRoute of
WWWorkflowR -> GWWWorkflowR
WWFilesR wpl stCID -> GWWFilesR wpl stCID
@ -47,12 +47,12 @@ _WorkflowScopeRoute = prism' (uncurry toRoute) toWorkflowScopeRoute
WorkflowInstanceListR -> SchoolWorkflowInstanceListR
WorkflowInstanceNewR -> SchoolWorkflowInstanceNewR
WorkflowInstanceR win subRoute -> SchoolWorkflowInstanceR win $ case subRoute of
WIEditR -> SWIEditR
WIDeleteR -> SWIDeleteR
WIWorkflowsR -> SWIWorkflowsR
WIInitiateR -> SWIInitiateR
WIUpdateR -> SWIUpdateR
WorkflowWorkflowListR -> SchoolWorkflowWorkflowListR
WIEditR -> SWIEditR
WIDeleteR -> SWIDeleteR
WIWorkflowsR lState -> SWIWorkflowsR lState
WIInitiateR -> SWIInitiateR
WIUpdateR -> SWIUpdateR
WorkflowWorkflowListR lState -> SchoolWorkflowWorkflowListR lState
WorkflowWorkflowR wwCID subRoute -> SchoolWorkflowWorkflowR wwCID $ case subRoute of
WWWorkflowR -> SWWWorkflowR
WWFilesR wpl stCID -> SWWFilesR wpl stCID
@ -60,31 +60,31 @@ _WorkflowScopeRoute = prism' (uncurry toRoute) toWorkflowScopeRoute
WWDeleteR -> SWWDeleteR
other -> error $ "not implemented _WorkflowScopeRoute for: " <> show other
toWorkflowScopeRoute = \case
GlobalWorkflowInstanceListR -> Just ( WSGlobal, WorkflowInstanceListR )
GlobalWorkflowInstanceNewR -> Just ( WSGlobal, WorkflowInstanceNewR )
GlobalWorkflowInstanceR win subRoute -> Just . (WSGlobal, ) . WorkflowInstanceR win $ case subRoute of
GWIEditR -> WIEditR
GWIDeleteR -> WIDeleteR
GWIWorkflowsR -> WIWorkflowsR
GWIInitiateR -> WIInitiateR
GWIUpdateR -> WIUpdateR
GlobalWorkflowWorkflowListR -> Just ( WSGlobal, WorkflowWorkflowListR )
GlobalWorkflowWorkflowR wwCID subRoute -> Just . (WSGlobal, ) . WorkflowWorkflowR wwCID $ case subRoute of
GlobalWorkflowInstanceListR -> Just ( WSGlobal, WorkflowInstanceListR )
GlobalWorkflowInstanceNewR -> Just ( WSGlobal, WorkflowInstanceNewR )
GlobalWorkflowInstanceR win subRoute -> Just . ( WSGlobal, ) . WorkflowInstanceR win $ case subRoute of
GWIEditR -> WIEditR
GWIDeleteR -> WIDeleteR
GWIWorkflowsR lState -> WIWorkflowsR lState
GWIInitiateR -> WIInitiateR
GWIUpdateR -> WIUpdateR
GlobalWorkflowWorkflowListR lState -> Just ( WSGlobal, WorkflowWorkflowListR lState )
GlobalWorkflowWorkflowR wwCID subRoute -> Just . ( WSGlobal, ) . WorkflowWorkflowR wwCID $ case subRoute of
GWWWorkflowR -> WWWorkflowR
GWWFilesR wpl stCID -> WWFilesR wpl stCID
GWWEditR -> WWEditR
GWWDeleteR -> WWDeleteR
SchoolR ssh sRoute -> case sRoute of
SchoolWorkflowInstanceListR -> Just ( WSSchool ssh, WorkflowInstanceListR )
SchoolWorkflowInstanceNewR -> Just ( WSSchool ssh, WorkflowInstanceNewR )
SchoolWorkflowInstanceR win subRoute -> Just . (WSSchool ssh, ) . WorkflowInstanceR win $ case subRoute of
SWIEditR -> WIEditR
SWIDeleteR -> WIDeleteR
SWIWorkflowsR -> WIWorkflowsR
SWIInitiateR -> WIInitiateR
SWIUpdateR -> WIUpdateR
SchoolWorkflowWorkflowListR -> Just ( WSSchool ssh, WorkflowWorkflowListR )
SchoolWorkflowWorkflowR wwCID subRoute -> Just . (WSSchool ssh, ) . WorkflowWorkflowR wwCID $ case subRoute of
SchoolWorkflowInstanceListR -> Just ( WSSchool ssh, WorkflowInstanceListR )
SchoolWorkflowInstanceNewR -> Just ( WSSchool ssh, WorkflowInstanceNewR )
SchoolWorkflowInstanceR win subRoute -> Just . ( WSSchool ssh, ) . WorkflowInstanceR win $ case subRoute of
SWIEditR -> WIEditR
SWIDeleteR -> WIDeleteR
SWIWorkflowsR lState -> WIWorkflowsR lState
SWIInitiateR -> WIInitiateR
SWIUpdateR -> WIUpdateR
SchoolWorkflowWorkflowListR lState -> Just ( WSSchool ssh, WorkflowWorkflowListR lState )
SchoolWorkflowWorkflowR wwCID subRoute -> Just . ( WSSchool ssh, ) . WorkflowWorkflowR wwCID $ case subRoute of
SWWWorkflowR -> WWWorkflowR
SWWFilesR wpl stCID -> WWFilesR wpl stCID
SWWEditR -> WWEditR

View File

@ -48,9 +48,10 @@ workflowInstanceInitiateR rScope win = workflowsDisabledWarning MsgWorkflowInsta
wwId <- insert WorkflowWorkflow
{ workflowWorkflowInstance = Just wiId
, workflowWorkflowScope = workflowInstanceScope
, workflowWorkflowGraph = workflowInstanceGraph
, workflowWorkflowScope = workflowInstanceScope
, workflowWorkflowGraph = workflowInstanceGraph
, workflowWorkflowState
, workflowWorkflowArchived = Nothing -- FIXME: set to now + 2 months if current state is final state
}
return . Just $ do
@ -65,7 +66,7 @@ workflowInstanceInitiateR rScope win = workflowsDisabledWarning MsgWorkflowInsta
cID <- encrypt wwId
redirectAlternatives $ NonEmpty.fromList
[ _WorkflowScopeRoute # ( rScope, WorkflowWorkflowR cID WWWorkflowR )
, _WorkflowScopeRoute # ( rScope, WorkflowInstanceR workflowInstanceName WIWorkflowsR )
, _WorkflowScopeRoute # ( rScope, WorkflowInstanceR workflowInstanceName $ WIWorkflowsR WorkflowWorkflowListActive )
, _WorkflowScopeRoute # ( rScope, WorkflowInstanceListR )
]

View File

@ -177,7 +177,7 @@ workflowInstanceListR rScope = workflowsDisabledWarning title heading $ do
where
toInitiateRoute win = _WorkflowScopeRoute # (rScope, WorkflowInstanceR win WIInitiateR)
toEditRoute win = _WorkflowScopeRoute # (rScope, WorkflowInstanceR win WIEditR)
toListRoute win = _WorkflowScopeRoute # (rScope, WorkflowInstanceR win WIWorkflowsR)
toListRoute win = _WorkflowScopeRoute # (rScope, WorkflowInstanceR win $ WIWorkflowsR WorkflowWorkflowListActive)
toUpdateRoute win = _WorkflowScopeRoute # (rScope, WorkflowInstanceR win WIUpdateR)
(heading, title) = case rScope of
@ -241,7 +241,7 @@ getTopWorkflowInstanceListR = workflowsDisabledWarning title heading $ do
where
toInitiateRoute' rScope win = _WorkflowScopeRoute # (rScope, WorkflowInstanceR win WIInitiateR)
toEditRoute' rScope win = _WorkflowScopeRoute # (rScope, WorkflowInstanceR win WIEditR)
toListRoute' rScope win = _WorkflowScopeRoute # (rScope, WorkflowInstanceR win WIWorkflowsR)
toListRoute' rScope win = _WorkflowScopeRoute # (rScope, WorkflowInstanceR win $ WIWorkflowsR WorkflowWorkflowListActive)
toUpdateRoute' rScope win = _WorkflowScopeRoute # (rScope, WorkflowInstanceR win WIUpdateR)
(title, heading) = (MsgTopWorkflowInstancesTitle, MsgTopWorkflowInstancesHeading)

View File

@ -1,10 +1,10 @@
{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
module Handler.Workflow.Workflow.List
( getGlobalWorkflowWorkflowListR
( getGlobalWorkflowWorkflowListR
, getSchoolWorkflowWorkflowListR
, workflowWorkflowListR
, getGWIWorkflowsR
, getGWIWorkflowsR
, getSWIWorkflowsR
, workflowInstanceWorkflowsR
, getAdminWorkflowWorkflowListR
@ -55,46 +55,63 @@ instance Default WorkflowWorkflowListFilterProj where
, wwProjFilterFinal = Nothing
}
makeLenses_ ''WorkflowWorkflowListFilterProj
makeLenses_ ''WorkflowWorkflowListFilterProj
getGlobalWorkflowWorkflowListR :: Handler Html
restrictOnArchived :: E.SqlExpr (Entity WorkflowWorkflow) -> UTCTime -> WorkflowWorkflowListType -> E.SqlExpr (E.Value Bool)
restrictOnArchived _ _ WorkflowWorkflowListAll = E.true
restrictOnArchived workflowWorkflow now wwListType = E.maybe
(E.val $ wwListType /= WorkflowWorkflowListArchive)
(\archivedOn -> if wwListType == WorkflowWorkflowListArchive then archivedOn E.<=. E.val now else E.val now E.<. archivedOn)
(workflowWorkflow E.^. WorkflowWorkflowArchived)
getGlobalWorkflowWorkflowListR :: WorkflowWorkflowListType -> Handler Html
getGlobalWorkflowWorkflowListR = workflowWorkflowListR WSGlobal
getSchoolWorkflowWorkflowListR :: SchoolId -> Handler Html
getSchoolWorkflowWorkflowListR :: SchoolId -> WorkflowWorkflowListType -> Handler Html
getSchoolWorkflowWorkflowListR = workflowWorkflowListR . WSSchool
workflowWorkflowListR :: RouteWorkflowScope -> Handler Html
workflowWorkflowListR rScope = workflowsDisabledWarning (headings ^. _1) (headings ^. _2) $ do
workflowWorkflowListR :: RouteWorkflowScope
-> WorkflowWorkflowListType
-> Handler Html
workflowWorkflowListR rScope wwListType = workflowsDisabledWarning (headings ^. _1) (headings ^. _2) $ do
now <- liftIO getCurrentTime
scope <- runDB . maybeT notFound $ fromRouteWorkflowScope rScope
workflowWorkflowList headings columns . runReader $ do
workflowWorkflow <- view queryWorkflowWorkflow
return $ workflowWorkflow E.^. WorkflowWorkflowScope E.==. E.val (scope ^. _DBWorkflowScope)
return $
workflowWorkflow E.^. WorkflowWorkflowScope E.==. E.val (scope ^. _DBWorkflowScope)
E.&&. restrictOnArchived workflowWorkflow now wwListType
where
columns = def
{ wwListColumnScope = False
}
headings = (MsgWorkflowWorkflowListScopeTitle rScope, MsgWorkflowWorkflowListScopeHeading rScope)
headings = (MsgWorkflowWorkflowListScopeTitle rScope wwListType, MsgWorkflowWorkflowListScopeHeading rScope wwListType)
getGWIWorkflowsR :: WorkflowInstanceName -> Handler Html
getGWIWorkflowsR :: WorkflowInstanceName -> WorkflowWorkflowListType -> Handler Html
getGWIWorkflowsR = workflowInstanceWorkflowsR WSGlobal
getSWIWorkflowsR :: SchoolId -> WorkflowInstanceName -> Handler Html
getSWIWorkflowsR ssh = workflowInstanceWorkflowsR $ WSSchool ssh
getSWIWorkflowsR :: SchoolId -> WorkflowInstanceName -> WorkflowWorkflowListType -> Handler Html
getSWIWorkflowsR = workflowInstanceWorkflowsR . WSSchool
workflowInstanceWorkflowsR :: RouteWorkflowScope -> WorkflowInstanceName -> Handler Html
workflowInstanceWorkflowsR rScope win = workflowsDisabledWarning (MsgWorkflowWorkflowListNamedInstanceTitleDisabled rScope) (MsgWorkflowWorkflowListNamedInstanceHeadingDisabled rScope) $ do
workflowInstanceWorkflowsR :: RouteWorkflowScope
-> WorkflowInstanceName
-> WorkflowWorkflowListType
-> Handler Html
workflowInstanceWorkflowsR rScope win wwListType = workflowsDisabledWarning (MsgWorkflowWorkflowListNamedInstanceTitleDisabled rScope wwListType) (MsgWorkflowWorkflowListNamedInstanceHeadingDisabled rScope wwListType) $ do
now <- liftIO getCurrentTime
(scope, desc) <- runDB $ do
scope <- maybeT notFound $ fromRouteWorkflowScope rScope
wiId <- getKeyBy404 . UniqueWorkflowInstance win $ scope ^. _DBWorkflowScope
desc <- selectWorkflowInstanceDescription wiId
return (scope, desc)
let headings = case desc of
Nothing -> (MsgWorkflowWorkflowListInstanceTitle, MsgWorkflowWorkflowListInstanceHeading)
Nothing -> (MsgWorkflowWorkflowListInstanceTitle wwListType, MsgWorkflowWorkflowListInstanceHeading wwListType)
Just (Entity _ WorkflowInstanceDescription{..})
-> ( MsgWorkflowWorkflowListNamedInstanceTitle rScope workflowInstanceDescriptionTitle
, MsgWorkflowWorkflowListNamedInstanceHeading rScope workflowInstanceDescriptionTitle
-> ( MsgWorkflowWorkflowListNamedInstanceTitle rScope workflowInstanceDescriptionTitle wwListType
, MsgWorkflowWorkflowListNamedInstanceHeading rScope workflowInstanceDescriptionTitle wwListType
)
workflowWorkflowList headings columns . runReader $ do
workflowWorkflow <- view queryWorkflowWorkflow
@ -102,6 +119,7 @@ workflowInstanceWorkflowsR rScope win = workflowsDisabledWarning (MsgWorkflowWor
E.where_ $ workflowInstance E.^. WorkflowInstanceName E.==. E.val win
E.&&. workflowInstance E.^. WorkflowInstanceScope E.==. E.val (scope ^. _DBWorkflowScope)
E.&&. workflowWorkflow E.^. WorkflowWorkflowInstance E.==. E.just (workflowInstance E.^. WorkflowInstanceId)
E.&&. restrictOnArchived workflowWorkflow now wwListType
where
columns = def
{ wwListColumnInstance = False
@ -113,10 +131,14 @@ getAdminWorkflowWorkflowListR :: Handler Html
getAdminWorkflowWorkflowListR = workflowWorkflowList headings def $ const E.true
where headings = (MsgAdminWorkflowWorkflowListTitle, MsgAdminWorkflowWorkflowListHeading)
getTopWorkflowWorkflowListR :: Handler Html
getTopWorkflowWorkflowListR = workflowsDisabledWarning (headings ^. _1) (headings ^. _2) . workflowWorkflowList headings def . views queryWorkflowWorkflow $ isTopWorkflowScopeSql . (E.^. WorkflowWorkflowScope)
where headings = (MsgWorkflowWorkflowListTopTitle, MsgWorkflowWorkflowListTopHeading)
getTopWorkflowWorkflowListR :: WorkflowWorkflowListType -> Handler Html
getTopWorkflowWorkflowListR = topWorkflowWorkflowListR
topWorkflowWorkflowListR :: WorkflowWorkflowListType -> Handler Html
topWorkflowWorkflowListR wwListType = do
now <- liftIO getCurrentTime
workflowsDisabledWarning (headings ^. _1) (headings ^. _2) . workflowWorkflowList headings def . views queryWorkflowWorkflow $ \workflowWorkflow -> isTopWorkflowScopeSql (workflowWorkflow E.^. WorkflowWorkflowScope) E.&&. restrictOnArchived workflowWorkflow now wwListType
where headings = (MsgWorkflowWorkflowListTopTitle wwListType, MsgWorkflowWorkflowListTopHeading wwListType)
type WorkflowWorkflowTableExpr = E.SqlExpr (Entity WorkflowWorkflow)
`E.LeftOuterJoin` E.SqlExpr (Maybe (Entity WorkflowInstance))
@ -361,12 +383,12 @@ workflowWorkflowList (title, heading) WWListColumns{..} sqlPred = do
anchorWorkflowScope f = maybeAnchorCellM <$> mkLink <*> f
where mkLink = runReaderT $ do
rScope <- hoistMaybe =<< view resultRouteScope
return $ _WorkflowScopeRoute # (rScope, WorkflowWorkflowListR)
return $ _WorkflowScopeRoute # (rScope, WorkflowWorkflowListR WorkflowWorkflowListActive)
anchorWorkflowInstance f = maybeAnchorCellM <$> mkLink <*> f
where mkLink = runReaderT $ do
rScope <- hoistMaybe =<< view resultRouteScope
win <- hoistMaybe =<< preview (resultWorkflowInstance . _Just . _entityVal . _workflowInstanceName)
return $ _WorkflowScopeRoute # (rScope, WorkflowInstanceR win WIWorkflowsR)
return $ _WorkflowScopeRoute # (rScope, WorkflowInstanceR win $ WIWorkflowsR WorkflowWorkflowListActive)
dbtSorting = mconcat
[ singletonMap "workflow-workflow" . SortProjected . comparing $ view resultWorkflowWorkflowId
, singletonMap "scope" . SortProjected . comparing $ view resultRouteScope

View File

@ -52,6 +52,7 @@ data WorkflowHistoryItem = WorkflowHistoryItem
data WorkflowCurrentState = WorkflowCurrentState
{ wcsState :: Maybe (Text, Maybe Icon)
, wcsArchived :: Maybe UTCTime
, wcsMessages :: Set Message
, wcsPayload :: [(Text, ([WorkflowFieldPayloadW Void (Maybe (Entity User))], Maybe Text))]
}
@ -76,12 +77,13 @@ getSWWFilesR ssh = getWorkflowFilesR $ WSSchool ssh
workflowR :: RouteWorkflowScope -> CryptoFileNameWorkflowWorkflow -> Handler Html
workflowR rScope cID = workflowsDisabledWarning title heading $ do
now <- liftIO getCurrentTime
(mEdge, (workflowState, workflowHistory)) <- runDB $ do
wwId <- decrypt cID
WorkflowWorkflow{..} <- get404 wwId
maybeT notFound . void . assertM (== review _DBWorkflowScope workflowWorkflowScope) $ fromRouteWorkflowScope rScope
mEdgeForm <- workflowEdgeForm (Right wwId) Nothing
wGraph <- getSharedIdWorkflowGraph workflowWorkflowGraph
wGraph@WorkflowGraph{..} <- getSharedIdWorkflowGraph workflowWorkflowGraph
let canonRoute = _WorkflowScopeRoute # (rScope, WorkflowWorkflowR cID WWWorkflowR)
mEdge <- for mEdgeForm $ \edgeForm -> do
@ -94,7 +96,15 @@ workflowR rScope cID = workflowsDisabledWarning title heading $ do
wiScope <- maybeT notFound . toRouteWorkflowScope $ _DBWorkflowScope # workflowInstanceScope
return (wiScope, Entity wiId wInstance)
update wwId [ WorkflowWorkflowState =. view _DBWorkflowState nState ]
wwArchived <- lift . maybeT (pure Nothing) $ do
archiveAfter <- MaybeT . getsYesod $ view _appWorkflowWorkflowArchiveAfter
let WorkflowAction{wpTo,wpTime} = last nState
WGN{wgnFinal} <- hoistMaybe $ Map.lookup wpTo wgNodes
return $ const (archiveAfter `addUTCTime` wpTime) <$> wgnFinal
update wwId [ WorkflowWorkflowState =. view _DBWorkflowState nState
, WorkflowWorkflowArchived =. wwArchived
]
return . Just $ do
whenIsJust wInstance $ \(wiScope, Entity _ WorkflowInstance{..}) -> do
@ -204,10 +214,11 @@ workflowR rScope cID = workflowsDisabledWarning title heading $ do
messageContent <- selectLanguageI18n wnmContent
return Message{..}
let wcsArchived = workflowWorkflowArchived
tell ( Just $ Last WorkflowCurrentState{..}
, pure WorkflowHistoryItem{..}
)
WorkflowGraph{..} = wGraph
wState = review _DBWorkflowState workflowWorkflowState
in fmap (over _2 (sortOn (Down . whiTime) . reverse) . view _2) . runConduit $ sourceWorkflowActionInfos wwId wState .| execRWSC () Map.empty (C.mapM_ go)
return (mEdge, (workflowState, workflowHistory))
@ -248,6 +259,7 @@ workflowR rScope cID = workflowsDisabledWarning title heading $ do
Nothing -> i18n MsgWorkflowPayloadUserGone
Just (Entity _ User{..}) -> nameWidget userDisplayName userSurname
WorkflowFieldPayloadW (WFPFile v ) -> absurd v
archivationScheduled archived = $(i18nWidgetFile "workflow-archivation-scheduled")
$(widgetFile "workflows/workflow")
where
(heading, title) = case rScope of

View File

@ -103,9 +103,7 @@ data ManualMigration
| Migration20210208StudyFeaturesRelevanceCachedUUIDs
| Migration20210318CrontabSubmissionRatedNotification
| Migration20210608SeparateTermActive
-- TODO: migration regarding authorship statements
-- - apply desired non-default modes for IfI
-- - set authorship statement texts for IfI
| Migration20220521WorkflowArchivation
deriving (Eq, Ord, Read, Show, Enum, Bounded, Generic, Typeable)
deriving anyclass (Universe, Finite)
@ -1069,6 +1067,20 @@ customMigrations = mapF $ \case
ALTER TABLE "term" DROP COLUMN "active";
|]
Migration20220521WorkflowArchivation -> whenM (and2M (tableExists "workflow_workflow") $ not <$> columnExists "workflow_workflow" "archived") $ do
now <- liftIO getCurrentTime
-- mArchiveAfter <- lift $ view _appWorkflowWorkflowArchiveAfter
let mArchiveAfter = Just (5270400 :: NominalDiffTime)
[executeQQ| ALTER TABLE "workflow_workflow" ADD "archived" timestamp with time zone; |]
let getWorkflows = [queryQQ| SELECT "workflow_workflow"."id", "workflow_workflow"."state"->-1->'time', "workflow_workflow"."state"->-1->'to', "shared_workflow_graph"."graph" FROM "workflow_workflow" INNER JOIN "shared_workflow_graph" ON "workflow_workflow"."graph" = "shared_workflow_graph"."hash"; |]
migrateArchived [ fromPersistValue -> Right (wwId :: WorkflowWorkflowId), fmap Aeson.fromJSON . fromPersistValue -> Right (Aeson.Success wpTime), fmap Aeson.fromJSON . fromPersistValue -> Right (Aeson.Success wpTo), fromPersistValue -> Right (wGraph :: DBWorkflowGraph) ] = maybeT (return ()) $ do
archiveAfter <- hoistMaybe mArchiveAfter
WGN{wgnFinal} <- hoistMaybe . Map.lookup wpTo $ wgNodes wGraph
let wwArchived = const (max now $ archiveAfter `addUTCTime` wpTime) <$> wgnFinal
lift [executeQQ| UPDATE "workflow_workflow" SET "archived" = #{wwArchived} WHERE "id" = #{wwId}; |]
migrateArchived _ = return ()
in runConduit $ getWorkflows .| C.mapM_ migrateArchived
tableExists :: MonadIO m => Text -> ReaderT SqlBackend m Bool
tableExists table = do

View File

@ -32,6 +32,7 @@ module Model.Types.Workflow
, WorkflowFieldPayload(..), _WorkflowFieldPayload
, workflowStatePayload, workflowStateCurrentPayloads
, WorkflowChildren
, WorkflowWorkflowListType(..)
) where
import Import.NoModel
@ -438,7 +439,8 @@ classifyWorkflowScope = \case
WSTermSchool{} -> WSTermSchool'
WSCourse{} -> WSCourse'
----- WORKFLOW: PAYLOAD -----
----- WORKFLOW PAYLOAD -----
newtype WorkflowPayloadLabel = WorkflowPayloadLabel { unWorkflowPayloadLabel :: CI Text }
deriving stock (Eq, Ord, Show, Read, Data, Generic, Typeable)
@ -675,10 +677,19 @@ workflowStateCurrentPayloads :: forall fileid userid mono.
-> Map WorkflowPayloadLabel (Set (WorkflowFieldPayloadW fileid userid))
workflowStateCurrentPayloads = Map.unionsWith (\_ v -> v) . map wpPayload . otoList
----- Workflow routing types -----
data WorkflowWorkflowListType = WorkflowWorkflowListActive | WorkflowWorkflowListArchive | WorkflowWorkflowListAll
deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic, Typeable)
deriving anyclass (Universe, Finite)
----- Lenses needed here -----
makeLenses_ ''WorkflowAction
----- Generic traversal -----
type family Concat as bs where
@ -824,6 +835,8 @@ derivePathPiece ''WorkflowScope (camelToPathPiece' 1) "--"
nullaryPathPiece ''WorkflowPayloadTimeCapturePrecision $ camelToPathPiece' 2
nullaryPathPiece ''WorkflowWorkflowListType $ camelToPathPiece' 3
----- ToJSON / FromJSON instances -----
omitNothing :: [JSON.Pair] -> [JSON.Pair]
@ -1229,6 +1242,7 @@ instance (Ord fileid, FromJSON fileid, FromJSON userid, Typeable fileid, Typeabl
uid <- o JSON..: toPathPiece WFPUser'
return $ WorkflowFieldPayloadW $ WFPUser uid
pathPieceJSON ''WorkflowWorkflowListType
----- PersistField / PersistFieldSql instances -----

View File

@ -232,6 +232,8 @@ data AppSettings = AppSettings
, appJobMaxFlush :: Maybe Natural
, appCommunicationAttachmentsMaxSize :: Maybe Natural
, appWorkflowWorkflowArchiveAfter :: Maybe NominalDiffTime
} deriving Show
data JobMode = JobsLocal { jobsAcceptOffload :: Bool }
@ -707,6 +709,8 @@ instance FromJSON AppSettings where
appCommunicationAttachmentsMaxSize <- o .:? "communication-attachments-max-size"
appWorkflowWorkflowArchiveAfter <- o .:? "workflow-workflow-archive-after"
return AppSettings{..}
where isValidARCConf ARCConf{..} = arccMaximumWeight > 0

View File

@ -200,12 +200,14 @@ getWorkflowWorkflowState' wwId Nothing = withReaderT (projectBackend @SqlBackend
, workflowWorkflow E.^. WorkflowWorkflowScope
, workflowWorkflow E.^. WorkflowWorkflowGraph
, E.veryUnsafeCoerceSqlExprValue $ workflowWorkflow E.^. WorkflowWorkflowState
, workflowWorkflow E.^. WorkflowWorkflowArchived
)
let
( E.Value workflowWorkflowInstance
, E.Value workflowWorkflowScope
, E.Value workflowWorkflowGraph
, E.Value (wwState :: PersistValue) -- Don't parse
, E.Value workflowWorkflowArchived
) = res
wwState' <- memcachedBy Nothing (WorkflowWorkflowStateParse wwState) . return $ fromPersistValue wwState
case wwState' of

View File

@ -0,0 +1,11 @@
$newline never
$maybe archived <- appWorkflowWorkflowArchiveAfter
Workflows werden nun automatisch archiviert, sobald sie #
$if archived /= 0
seit #{tshow (nominalDiffTimeToSeconds archived / 86400)} Tagen #
abgeschlossen sind.
$nothing
Workflows können nun archiviert werden.
<br>
Archivierte Workflows werden nicht mehr in der Liste laufender Workflows angezeigt, sondern sind über ein separates Archiv verfügbar.

View File

@ -0,0 +1,13 @@
$newline never
$maybe archived <- appWorkflowWorkflowArchiveAfter
Workflows are now being archived automatically #
$if archived == 0
immediately #
$else
#{tshow (nominalDiffTimeToSeconds archived / 86400)} days #
after finalization.
$nothing
Workflow may now be archived.
<br>
Archived workflows are not shown among the list of running workflows, but can instead be accessed via a separate archive list.

View File

@ -0,0 +1,9 @@
$newline never
<p>
Dieser Workflow wird am ^{formatTimeW SelFormatDateTime archived} archiviert, sofern keine weitere Aktion durchgeführt wird.
<p>
Sobald ein Workflow archiviert ist, wird er nicht mehr in der Liste laufender Workflows angeführt.
<br>
Sie können in einem bereits archivierten Workflow auch weiterhin alle Aktionen ausführen, welche Sie in einem laufenden Workflow im gleichen Zustand durchführen könnten.

View File

@ -0,0 +1,9 @@
$newline never
<p>
This workflow will be archived on ^{formatTimeW SelFormatDateTime archived} if no further action is performed.
<p>
Once a workflow has been archived, it will not be listed among the list of running workflows anymore.
<br>
In an archived workflow, you are still able to perform any action that you could perform in a running workflow in the same current state.

View File

@ -1,6 +1,10 @@
$newline never
$maybe WorkflowCurrentState{..} <- workflowState
<section>
$maybe archived <- wcsArchived
$if now < archived
^{notification NotificationBroad =<< messageWidget Warning (archivationScheduled archived)}
<h2>
_{MsgWorkflowWorkflowWorkflowStateHeading}
@ -16,6 +20,13 @@ $maybe WorkflowCurrentState{..} <- workflowState
$nothing
<span .workflow-state--state-special>
_{MsgWorkflowWorkflowWorkflowStateStateHidden}
$maybe archived <- wcsArchived
$if now >= archived
<dt .deflist__dt>
_{MsgWorkflowWorkflowWorkflowStateArchivedLabel} #
^{messageTooltip =<< messageI Info MsgWorkflowWorkflowWorkflowArchivationInfo}
<dd .deflist__dd>
^{formatTimeW SelFormatDateTime archived}
$forall msg <- wcsMessages
^{notification NotificationBroad msg}