diff --git a/kthelp/.htaccess b/kthelp/.htaccess new file mode 100644 index 0000000..2c1b49f --- /dev/null +++ b/kthelp/.htaccess @@ -0,0 +1,3 @@ +Order deny,allow +Deny from all + diff --git a/kthelp/ktcore/EN/admin/workflow/overview.html b/kthelp/ktcore/EN/admin/workflow/overview.html new file mode 100644 index 0000000..b5b0cd8 --- /dev/null +++ b/kthelp/ktcore/EN/admin/workflow/overview.html @@ -0,0 +1,25 @@ + + + + + + Workflow Overview + + + + +

Workflow Overview

+ +

Workflow allows you to assign a series of steps to the document creation and +management process. For example, a "News" workflow might have documents which +go from Research to Draft to Under Review +to Published, +with different people participating in the document's +lifecycle at each stage.  Naturally, not all documents have the +same needs in terms of workflow:  Invoices (which must be drawn up, mailed, and then marked as paid) are very different from Marketing documents. 

+

To facilitate this, KnowledgeTree™ allows the Administrator to +define a number of different workflows, each of which can be applied to +different documents as their organisation requires.

+ + + diff --git a/lib/browse/BrowseColumns.inc.php b/lib/browse/BrowseColumns.inc.php index c318442..0ab38a4 100644 --- a/lib/browse/BrowseColumns.inc.php +++ b/lib/browse/BrowseColumns.inc.php @@ -72,7 +72,7 @@ class TitleColumn extends BrowseColumn { function renderFolderLink($aDataRow) { $outStr = ''; $outStr .= $aDataRow["folder"]->getName(); - $outStr .= ''; + $outStr .= ' '; return $outStr; } diff --git a/plugins/ktcore/KTDocumentActions.php b/plugins/ktcore/KTDocumentActions.php index 7f483cf..bd92476 100644 --- a/plugins/ktcore/KTDocumentActions.php +++ b/plugins/ktcore/KTDocumentActions.php @@ -585,7 +585,7 @@ class KTDocumentWorkflowAction extends KTDocumentAction { $oUser =& User::get($_SESSION['userID']); $aTransitions = KTWorkflowUtil::getTransitionsForDocumentUser($oDocument, $oUser); - $aWorkflows = KTWorkflow::getList(); + $aWorkflows = KTWorkflow::getList('start_state_id IS NOT NULL'); $fieldErrors = null; diff --git a/plugins/ktcore/admin/workflows.php b/plugins/ktcore/admin/workflows.php index 2b19a00..defcae5 100755 --- a/plugins/ktcore/admin/workflows.php +++ b/plugins/ktcore/admin/workflows.php @@ -18,16 +18,232 @@ require_once(KT_LIB_DIR . '/search/savedsearch.inc.php'); require_once(KT_LIB_DIR . '/actions/documentaction.inc.php'); +require_once(KT_LIB_DIR . '/widgets/portlet.inc.php'); + +class WorkflowNavigationPortlet extends KTPortlet { + var $oWorkflow; + + function WorkflowNavigationPortlet($sTitle, $oWorkflow = null) { + $this->oWorkflow = $oWorkflow; + parent::KTPortlet($sTitle); + } + + function render() { + if (is_null($this->oWorkflow)) { return _('No Workflow Selected.'); } + + $aAdminPages = array(); + $aAdminPages[] = array('name' => _('Overview'), 'url' => $_SERVER['PHP_SELF'] . '?action=editWorkflow&fWorkflowId=' . $this->oWorkflow->getId()); + $aAdminPages[] = array('name' => _('States'), 'url' => $_SERVER['PHP_SELF'] . '?action=manageStates&fWorkflowId=' . $this->oWorkflow->getId()); + $aAdminPages[] = array('name' => _('Transitions'), 'url' => $_SERVER['PHP_SELF'] . '?action=manageTransitions&fWorkflowId=' . $this->oWorkflow->getId()); + $aAdminPages[] = array('name' => _('Actions'), 'url' => $_SERVER['PHP_SELF'] . '?action=manageActions&fWorkflowId=' . $this->oWorkflow->getId()); + + + $oTemplating = new KTTemplating; + $oTemplate = $oTemplating->loadTemplate("ktcore/workflow/admin_portlet"); + $aTemplateData = array( + "context" => $this, + "aAdminPages" => $aAdminPages, + ); + + return $oTemplate->render($aTemplateData); + } +} + class KTWorkflowDispatcher extends KTAdminDispatcher { var $bAutomaticTransaction = true; + var $sHelpPage = 'ktcore/admin/workflow/overview.html'; + var $aWorkflowInfo; + var $oWorkflow; - // {{{ WORKFLOW HANDLING - // {{{ do_main - function do_main () { + function check() { $this->aBreadcrumbs[] = array( 'url' => $_SERVER['PHP_SELF'], 'name' => _('Workflows'), ); + $this->oWorkflow =& KTWorkflow::get($_REQUEST['fWorkflowId']); + if (!PEAR::isError($this->oWorkflow)) { + $this->aBreadcrumbs[] = array( + 'url' => $_SERVER['PHP_SELF'], + 'query' => 'action=editWorkflow&fWorkflowId=' . $this->oWorkflow->getId(), + 'name' => $this->oWorkflow->getName(), + ); + $this->oPage->addPortlet(new WorkflowNavigationPortlet(_('Workflow'), $this->oWorkflow)); + } + + return true; + } + + // helper function to construct the set of workflow information + function buildWorkflowInfo($oWorkflow) { + if ($this->aWorkflowInfo != null) { return $this->aWorkflowInfo; } + + $aInfo = array(); + $aInfo['workflow'] = $oWorkflow; + + // roles + $aRoles = Role::getList(); + $aKeyRoles = array(); + foreach ($aRoles as $oRole) { $aKeyRoles[$oRole->getId()] = $oRole; } + $aInfo['roles'] = $aKeyRoles; + + // groups + $aGroups = Group::getList(); + $aKeyGroups = array(); + foreach ($aGroups as $oGroup) { $aKeyGroups[$oGroup->getId()] = $oGroup; } + $aInfo['groups'] = $aKeyGroups; + + // states. + $aStates = KTWorkflowState::getByWorkflow($oWorkflow); + $aKeyStates = array(); + foreach ($aStates as $oState) { $aKeyStates[$oState->getId()] = $oState; } + $aInfo['states'] = $aKeyStates; + + // transitions + $aTransitions = KTWorkflowTransition::getByWorkflow($oWorkflow); + $aKeyTransitions = array(); + foreach ($aTransitions as $oTransition) { $aKeyTransitions[$oTransition->getId()] = $oTransition; } + $aInfo['transitions'] = $aKeyTransitions; + + // permissions + $aPermissions = KTPermission::getList(); + $aKeyPermissions = array(); + foreach ($aPermissions as $oPermission) { $aKeyPermissions[$oPermission->getId()] = $oPermission; } + $aInfo['permissions'] = $aKeyPermissions; + + // actions + $aInfo['actions'] = KTDocumentActionUtil::getAllDocumentActions(); + $aKeyActions = array(); + foreach ($aInfo['actions'] as $oAction) { $aKeyActions[$oAction->getName()] = $oAction; } + $aInfo['actions_by_name'] = $aKeyActions; + + $aInfo['controlled_actions'] = KTWorkflowUtil::getControlledActionsForWorkflow($oWorkflow); + + /* + * now we need to do the crossmappings. + */ + + $aActionsByState = array(); + foreach ($aInfo['states'] as $oState) { + $aActionsByState[$oState->getId()] = KTWorkflowUtil::getEnabledActionsForState($oState);; + } + $aInfo['actions_by_state'] = $aActionsByState; + + // FIXME handle notified users and groups + $aTransitionsFromState = array(); + foreach ($aInfo['states'] as $oState) { + $aTransitionsFromState[$oState->getId()] = KTWorkflowUtil::getTransitionsFrom($oState); + } + $aInfo['transitions_from_state'] = $aTransitionsFromState; + + $aTransitionsToState = array(); + foreach ($aInfo['states'] as $oState) { + $aTransitionsToState[$oState->getId()] = KTWorkflowTransition::getByTargetState($oState); + } + $aInfo['transitions_to_state'] = $aTransitionsToState; + + $this->aWorkflowInfo = $aInfo; + + return $aInfo; + } + + + function getActionStringForState($oState) { + $aInfo = $this->aWorkflowInfo; + + // no controlled actions => all available + if (empty($aInfo['controlled_actions'])) { return _('All actions available.'); } + + + $aAlways = array(); + foreach ($aInfo['actions'] as $iActionId => $aAction) { + if (!array_key_exists($iActionId, $aInfo['controlled_actions'])) { + $aAlways[$iActionId] = $aAction; + } + } + + $aNamedActions = array(); + foreach ($aInfo['actions_by_state'][$oState->getId()] as $sName) { + $aNamedActions[] = $aInfo['actions_by_name'][$sName]; + } + + $aThese = array_merge($aAlways, $aNamedActions); + // some controlled. we need to be careful here: list actions that _are always_ available + if (empty($aThese)) { return _('No actions available.'); } + + // else + $aActions = array(); + foreach ($aThese as $oAction) { $aActions[] = $oAction->getDisplayName(); } + return implode(', ', $aActions); + } + + function getTransitionToStringForState($oState) { + $aInfo = $this->aWorkflowInfo; + //var_dump($aInfo['transitions_to_state'][$oState->getId()]); + if (($aInfo['workflow']->getStartStateId() != $oState->getId()) && (empty($aInfo['transitions_to_state'][$oState->getId()]))) { + return '' . _('This state is unreachable.') . ''; + } + + + if ($aInfo['workflow']->getStartStateId() == $oState->getId() && (empty($aInfo['transitions_to_state'][$oState->getId()]))) { + return '' . _('Documents start in this state') . ''; + } + $aT = array(); + if ($aInfo['workflow']->getStartStateId() == $oState->getId()) { + $aT[] = '' . _('Documents start in this state') . ''; + } + + foreach ($aInfo['transitions_to_state'][$oState->getId()] as $aTransition) { + $aT[] = sprintf('%s', $_SERVER['PHP_SELF'], $aInfo['workflow']->getId(), $aTransition->getId() ,$aTransition->getName()); + } + + return implode(', ',$aT); + } + + function getNotificationStringForState($oState) { + return _('No roles and groups notified.'); + } + + function transitionAvailable($oTransition, $oState) { + $aInfo = $this->aWorkflowInfo; + + $val = false; + foreach ($aInfo['transitions_from_state'][$oState->getId()] as $oT) { + if ($oTransition->getId() == $oT->getId()) { $val = true; } + } + + return $val; + } + + function actionAvailable($oAction, $oState) { + $aInfo = $this->aWorkflowInfo; + + $val = false; + + foreach ($aInfo['actions_by_state'][$oState->getId()] as $oA) { + + if ($oAction->getName() == $oA) { $val = true; } + } + + return $val; + } + + function getTransitionFromStringForState($oState) { + $aInfo = $this->aWorkflowInfo; + + if (empty($aInfo['transitions_from_state'][$oState->getId()])) { + return '' . _('No transitions available') . ''; + } + + $aT = array(); + foreach ($aInfo['transitions_from_state'][$oState->getId()] as $aTransition) { + $aT[] = sprintf('%s', $_SERVER['PHP_SELF'], $aInfo['workflow']->getId(), $aTransition->getId() ,$aTransition->getName()); + } + return implode(', ', $aT); + } + + // {{{ WORKFLOW HANDLING + // {{{ do_main + function do_main () { $add_fields = array(); $add_fields[] = new KTStringWidget(_('Name'),_('A human-readable name for the workflow.'), 'fName', null, $this->oPage, true); @@ -42,69 +258,57 @@ class KTWorkflowDispatcher extends KTAdminDispatcher { return $oTemplate; } // }}} - + // {{{ do_editWorkflow function do_editWorkflow() { $oTemplate =& $this->oValidator->validateTemplate('ktcore/workflow/editWorkflow'); $oWorkflow =& $this->oValidator->validateWorkflow($_REQUEST['fWorkflowId']); - $aStates = KTWorkflowState::getByWorkflow($oWorkflow); - $aPermissions = KTPermission::getList(); + + + $aInfo = $this->buildWorkflowInfo($oWorkflow); + + $aPermissions = $aInfo['permissions']; + $aStates = $aInfo['states']; $edit_fields = array(); $edit_fields[] = new KTStringWidget(_('Name'), _('A human-readable name for the workflow.'), 'fName', $oWorkflow->getName(), $this->oPage, true); $aOptions = array(); $vocab = array(); - $vocab[0] = 'None'; + $vocab[0] = 'None - documents cannot use this workflow.'; foreach($aStates as $state) { $vocab[$state->getId()] = $state->getName(); } - $aOptions['vocab'] = $vocab; - $edit_fields[] = new KTLookupWidget(_('Starting State'), _('When a document has this workflow applied to it, to which state should it initially be set'), 'fStartStateId', $oWorkflow->getStartStateId(), $this->oPage, false, null, null, $aOptions); + $aOptions['vocab'] = $vocab; + $edit_fields[] = new KTLookupWidget(_('Starting State'), _('When a document has this workflow applied to it, to which state should it initially be set. Note that workflows without a starting state cannot be applied to documents.'), 'fStartStateId', $oWorkflow->getStartStateId(), $this->oPage, false, null, null, $aOptions); + if (is_null($oWorkflow->getStartStateId())) { + $this->oPage->addInfo(_('This workflow is currently disabled. To enable it, please assign a starting state in the "Edit workflow properties" box.')); + } + /* $add_state_fields = array(); $add_state_fields[] = new KTStringWidget(_('Name'), _('A human-readable name for the state.'), 'fName', null, $this->oPage, true); - $add_transition_fields = array(); - $add_transition_fields[] = new KTStringWidget(_('Name'), _('A human-readable name for the transition.'), 'fName', null, $this->oPage, true); - $aOptions = array(); - $vocab = array(); - foreach($aStates as $state) { - $vocab[$state->getId()] = $state->getName(); - } - $aOptions['vocab'] = $vocab; - $add_transition_fields[] = new KTLookupWidget(_('Destination State'), _('Once this transition is complete, which state should the document be in?'), 'fTargetStateId', $oWorkflow->getStartStateId(), $this->oPage, true, null, null, $aOptions); - $aOptions = array(); - $vocab = array(); - foreach($aPermissions as $permission) { - $vocab[$permission->getId()] = $permission->getHumanName(); - } - $aOptions['vocab'] = $vocab; - $add_transition_fields[] = new KTLookupWidget(_('Guard Permission.'), _('Which permission must the user have in order to follow this transition?'), 'fPermissionId', $oWorkflow->getStartStateId(), $this->oPage, true, null, null, $aOptions); + */ + - $this->aBreadcrumbs[] = array( - 'url' => $_SERVER['PHP_SELF'], - 'name' => _('Workflows'), - ); - $this->aBreadcrumbs[] = array( - 'url' => $_SERVER['PHP_SELF'], - 'query' => 'action=editWorkflow&fWorkflowId=' . $oWorkflow->getId(), - 'name' => $oWorkflow->getName(), - ); $oTemplate->setData(array( + 'context' => $this, 'oWorkflow' => $oWorkflow, + 'aStates' => $aStates, - 'aTransitions' => KTWorkflowTransition::getByWorkflow($oWorkflow), + 'aTransitions' => $aInfo['transitions'], 'aPermissions' => $aPermissions, - 'aActions' => KTDocumentActionUtil::getAllDocumentActions(), - 'aActionsSelected' => KTWorkflowUtil::getControlledActionsForWorkflow($oWorkflow), + 'aActions' => $aInfo['actions'], + 'aActionsSelected' => $aInfo['controlled_actions'], + + // info + 'workflow_info' => $aInfo, - // fields + // subform 'edit_fields' => $edit_fields, - 'add_state_fields' => $add_state_fields, - 'add_transition_fields' => $add_transition_fields, )); return $oTemplate; } @@ -168,6 +372,137 @@ class KTWorkflowDispatcher extends KTAdminDispatcher { } // }}} + function do_manageActions() { + $oTemplate =& $this->oValidator->validateTemplate('ktcore/workflow/manageActions'); + $oWorkflow =& $this->oValidator->validateWorkflow($_REQUEST['fWorkflowId']); + + $aInfo = $this->buildWorkflowInfo($oWorkflow); + + $oTemplate->setData(array( + 'context' => $this, + 'oWorkflow' => $oWorkflow, + + 'aActions' => $aInfo['actions'], + 'aActionsSelected' => $aInfo['controlled_actions'], + + // info + 'workflow_info' => $aInfo, + )); + return $oTemplate; + + } + + function do_manageStates() { + $oTemplate =& $this->oValidator->validateTemplate('ktcore/workflow/manageStates'); + $oWorkflow =& $this->oValidator->validateWorkflow($_REQUEST['fWorkflowId']); + + $aInfo = $this->buildWorkflowInfo($oWorkflow); + + $add_fields = array(); + $add_fields[] = new KTStringWidget(_('Name'), _('A human-readable name for the state.'), 'fName', null, $this->oPage, true); + + + + $oTemplate->setData(array( + 'context' => $this, + 'oWorkflow' => $oWorkflow, + + // info + 'workflow_info' => $aInfo, + + // subform + 'add_fields' => $add_fields, + )); + return $oTemplate; + } + + function do_manageTransitions() { + $oTemplate =& $this->oValidator->validateTemplate('ktcore/workflow/manageTransitions'); + $oWorkflow =& $this->oValidator->validateWorkflow($_REQUEST['fWorkflowId']); + + $aInfo = $this->buildWorkflowInfo($oWorkflow); + + $add_transition_fields = array(); + $add_transition_fields[] = new KTStringWidget(_('Name'), _('A human-readable name for the transition.'), 'fName', null, $this->oPage, true); + $aOptions = array(); + $vocab = array(); + foreach($aInfo['states'] as $state) { + $vocab[$state->getId()] = $state->getName(); + } + $aOptions['vocab'] = $vocab; + $add_transition_fields[] = new KTLookupWidget(_('Destination State'), _('Once this transition is complete, which state should the document be in?'), 'fTargetStateId', $oWorkflow->getStartStateId(), $this->oPage, true, null, null, $aOptions); + $aOptions = array(); + $vocab = array(); + foreach($aInfo['permissions'] as $permission) { + $vocab[$permission->getId()] = $permission->getHumanName(); + } + $aOptions['vocab'] = $vocab; + $add_transition_fields[] = new KTLookupWidget(_('Guard Permission.'), _('Which permission must the user have in order to follow this transition?'), 'fPermissionId', $oWorkflow->getStartStateId(), $this->oPage, true, null, null, $aOptions); + + $oTemplate->setData(array( + 'context' => $this, + 'oWorkflow' => $oWorkflow, + + // info + 'workflow_info' => $aInfo, + + // subform + 'add_fields' => $add_transition_fields, + )); + return $oTemplate; + } + + function do_setTransitionAvailability() { + $oTemplate =& $this->oValidator->validateTemplate('ktcore/workflow/editWorkflow'); + $oWorkflow =& $this->oValidator->validateWorkflow($_REQUEST['fWorkflowId']); + + $transitionMap = (array) KTUtil::arrayGet($_REQUEST, 'fTransitionAvailability'); + + $aInfo = $this->buildWorkflowInfo($oWorkflow); + + $this->startTransaction(); + foreach ($aInfo['states'] as $oState) { + + $a = (array) $transitionMap[$oState->getId()]; + $transitions = array(); + foreach ($a as $tid => $on) { $transitions[] = $tid; } + + $res = KTWorkflowUtil::saveTransitionsFrom($oState, $transitions); + if (PEAR::isError($res)) { + $this->errorRedirectTo('manageTransitions', _('Error updating transitions:') . $res->getMessage(), sprintf('fWorkflowId=%d', $oWorkflow->getId())); + } + } + $this->commitTransaction(); + + $this->successRedirectTo('manageTransitions', _('Availability updated.'), sprintf('fWorkflowId=%d', $oWorkflow->getId())); + } + + + function do_updateActionAvailability() { + $oWorkflow =& $this->oValidator->validateWorkflow($_REQUEST['fWorkflowId']); + + $actionMap = (array) KTUtil::arrayGet($_REQUEST, 'fAvailableActions'); + + $aInfo = $this->buildWorkflowInfo($oWorkflow); + + $this->startTransaction(); + foreach ($aInfo['states'] as $oState) { + + $a = (array) $actionMap[$oState->getId()]; + $actions = array_keys($a); + + + + $res = KTWorkflowUtil::setEnabledActionsForState($oState, $actions); + if (PEAR::isError($res)) { + $this->errorRedirectTo('manageActions', _('Error updating actions:') . $res->getMessage(), sprintf('fWorkflowId=%d', $oWorkflow->getId())); + } + } + $this->commitTransaction(); + + $this->successRedirectTo('manageActions', _('Action availability updated.'), sprintf('fWorkflowId=%d', $oWorkflow->getId())); + } + // {{{ do_setWorkflowActions function do_setWorkflowActions() { $oWorkflow =& $this->oValidator->validateWorkflow($_REQUEST['fWorkflowId']); @@ -247,9 +582,14 @@ class KTWorkflowDispatcher extends KTAdminDispatcher { 'query' => 'action=editWorkflow&fWorkflowId=' . $oWorkflow->getId(), 'name' => $oWorkflow->getName(), ); - $this->oPage->setBreadcrumbDetails(_('state') . ': ' . $oState->getName()); + $this->oPage->setBreadcrumbDetails(_('State') . ': ' . $oState->getName()); $aInformed = KTWorkflowUtil::getInformedForState($oState); + + + $editForm = array(); + $editForm[] = new KTStringWidget(_('Name'), _('A human-readable name for this state. This is shown on the "Browse" page, as well as on the user\'s workflow page.'), 'fName', $oState->getName(), $this->oPage, true); + $oTemplate->setData(array( 'oWorkflow' => $oWorkflow, 'oState' => $oState, @@ -263,6 +603,7 @@ class KTWorkflowDispatcher extends KTAdminDispatcher { 'aRoles' => Role::getList(), 'aUsers' => User::getList(), 'aInformed' => $aInformed, + 'editForm' => $editForm, )); return $oTemplate; } @@ -402,7 +743,7 @@ class KTWorkflowDispatcher extends KTAdminDispatcher { 'redirect_to' => array('editWorkflow', 'fWorkflowId=' . $oWorkflow->getId()), 'message' => _('Could not create workflow transition'), )); - $this->successRedirectTo('editWorkflow', _('Workflow transition created'), 'fWorkflowId=' . $oWorkflow->getId()); + $this->successRedirectTo('editTransition', _('Workflow transition created'), sprintf('fWorkflowId=%d&fTransitionId=%d', $oWorkflow->getId(), $res->getId())); exit(0); } // }}} diff --git a/resources/css/kt-framing.css b/resources/css/kt-framing.css index 03f2962..3c9fbe5 100644 --- a/resources/css/kt-framing.css +++ b/resources/css/kt-framing.css @@ -103,6 +103,11 @@ body { border-bottom: 1px solid white; } + +.ktLoggedInUser { + font-weight: bold; +} + /* a.main_nav_item { background: transparent url(../../resources/graphics/home-navbar.gif) center left no-repeat; @@ -580,9 +585,9 @@ a.main_nav_item { .ktInfo { padding: 0 1em; - border: 1px solid #ffc21e; + border: 1px solid #c5c5c5; margin: 0.5em 0; - background: #ffdd80; + background: #dedede; } .ktInfo p { @@ -655,6 +660,8 @@ The text will be hidden for screen view. The generic fahrner-ish approach comes /* =========== standard listings. */ + + .listing td { padding: 0.5em; vertical-align: top; diff --git a/resources/css/workflow-admin.css b/resources/css/workflow-admin.css new file mode 100644 index 0000000..42c09d1 --- /dev/null +++ b/resources/css/workflow-admin.css @@ -0,0 +1,18 @@ +#workflow-states-list { + list-style-type: none; + margin-left: 0; + padding-left: 0; +} + +#workflow-states-list ul { + list-style-type: none; + margin-left: 0; + padding-left: 1em; + border-top: 1px solid #dedede; + margin-top: 0.5em; + margin-bottom: 1.5em; +} + +.workflow_element { + font-weight: bold; +} \ No newline at end of file diff --git a/templates/kt3/standard_page.smarty b/templates/kt3/standard_page.smarty index 05bc528..fc95fda 100644 --- a/templates/kt3/standard_page.smarty +++ b/templates/kt3/standard_page.smarty @@ -64,9 +64,7 @@
  • {if ($page->user)} - Logged in as {$page->user->getName()} - {else} - FIXME: page does not set user. + {$page->user->getName()} {/if} · diff --git a/templates/ktcore/help_with_edit.smarty b/templates/ktcore/help_with_edit.smarty index 6bd227f..470be8a 100644 --- a/templates/ktcore/help_with_edit.smarty +++ b/templates/ktcore/help_with_edit.smarty @@ -1,6 +1,9 @@ -

    Edit this help page.

    {if (!$help_body)}

    No content specified for this help file yet. Edit it first.

    {else} {$help_body} -{/if} \ No newline at end of file +{/if} + +
    +

    {i18n}Edit this help page.{/i18n}{i18n}Edit this help page.{/i18n}

    \ No newline at end of file diff --git a/templates/ktcore/metadata/listFieldsets.smarty b/templates/ktcore/metadata/listFieldsets.smarty index 8e698a6..81fe1ad 100644 --- a/templates/ktcore/metadata/listFieldsets.smarty +++ b/templates/ktcore/metadata/listFieldsets.smarty @@ -60,7 +60,7 @@ {$oWidget->render()} {/foreach} -
    diff --git a/templates/ktcore/workflow/admin_portlet.smarty b/templates/ktcore/workflow/admin_portlet.smarty new file mode 100644 index 0000000..341b48f --- /dev/null +++ b/templates/ktcore/workflow/admin_portlet.smarty @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/templates/ktcore/workflow/createState.smarty b/templates/ktcore/workflow/createState.smarty new file mode 100644 index 0000000..1137e4f --- /dev/null +++ b/templates/ktcore/workflow/createState.smarty @@ -0,0 +1,139 @@ +

    {i18n}New State{/i18n}

    + +

    As documents move through their lifecycle, they +are placed in certain states. For example, an invoice +which has been mailed might be in the "Pending" state after +the "sent" transition has been performed by a user.

    + +
    +
    +{i18n}Edit state properties{/i18n} + + + +{foreach item=oWidget from=$editForm} + {$oWidget->render()} +{/foreach} +
    + +
    +
    +
    + +
    + + + + +
    +{i18n}Inform Which Users?{/i18n} +

    {i18n}Please select which roles or groups should be +informed when this state is reached.{/i18n}

    + + +{if $aRoles} +

    {i18n}Roles{/i18n}

    +{entity_checkboxes entities=$aRoles name="fRoleIds" multiple="true" selected=$aInformed.role assign=aBoxes} +{foreach from=$aBoxes item=sBox} +{$sBox}
    +{/foreach} +{/if} + +

    {i18n}Groups{/i18n}

    +{entity_checkboxes entities=$aGroups name="fGroupIds" multiple="true" selected=$aInformed.group assign=aBoxes} +{foreach from=$aBoxes item=sBox} +{$sBox}
    +{/foreach} + +{* +

    {i18n}Users{/i18n}

    +{entity_checkboxes entities=$aUsers name="fUserIds" multiple="true" selected=$aInformed.user assign=aBoxes} +{foreach from=$aBoxes item=sBox} +{$sBox}
    +{/foreach} + + + +*} + +
    + + +{* +

    {i18n}Assigned Permissions{/i18n}

    +

    {i18n}While in this workflow state, additional permissions +may be given. This is done either to expose the document to more users +or to allow a particular role to be fulfilled before a workflow +transition can be accomplished.{/i18n}

    +*} + + +
    +{i18n}Transitions{/i18n} + +

    {i18n}Transitions are how documents move from one +state to another. Typically, most transitions can only be performed by people +with a specific role (e.g. Manager) or part of a specific group +(e.g. Marketing Department).{/i18n}

    + +{if $aTransitionsTo} +

    {i18n}Transitions to this state{/i18n}

    +{if (!empty($aTransitionsTo))} + + +{/if} +{else} +

    {i18n}No transitions lead to this state.{/i18n}

    +{/if} + +

    {i18n}Transitions from this state{/i18n}

    +
    + + + + +{if (!empty($aTransitions))} +{entity_checkboxes entities=$aTransitions name="fTransitionIds" multiple="true" selected=$aTransitionsSelected separator="
    "} +
    + +
    +{else} +

    {i18n}No transitions have been defined for this workflow.{/i18n}

    +{/if} +
    +
    + + + + +
    +
    +Actions allowed + + + + + +{if (!empty($aActions))} +
      +{entity_checkboxes name="fActions" entities=$aActions idmethod="getName" method="getDisplayName" assign="aCheckboxes" selected="$aActionsSelected"} +{foreach from=$aCheckboxes item=sCheckbox} +
    • {$sCheckbox}
    • +{/foreach} +
    +
    + +
    +{else} +No actions defined. +{/if} +
    +
    + diff --git a/templates/ktcore/workflow/documentWorkflow.smarty b/templates/ktcore/workflow/documentWorkflow.smarty index 430fbaa..f7b65b2 100644 --- a/templates/ktcore/workflow/documentWorkflow.smarty +++ b/templates/ktcore/workflow/documentWorkflow.smarty @@ -25,7 +25,7 @@ lifecycle of the document.{/i18n} {else}

    {i18n}No defined workflows{/i18n}

    -
    +

    {i18n}There are no defined workflows which can be started on this document. An administrator can create workflows to map the lifecycle of a document. Contact your administrator to discuss diff --git a/templates/ktcore/workflow/editState.smarty b/templates/ktcore/workflow/editState.smarty index 863cb5e..0589ce0 100644 --- a/templates/ktcore/workflow/editState.smarty +++ b/templates/ktcore/workflow/editState.smarty @@ -1,18 +1,25 @@

    {i18n}State{/i18n}: {$oState->getName()|escape}

    +

    As documents move through their lifecycle, they +are placed in certain states. For example, an invoice +which has been mailed might be in the "Pending" state after +the "sent" transition has been performed by a user.

    +
    {i18n}Edit state properties{/i18n} - +{foreach item=oWidget from=$editForm} + {$oWidget->render()} +{/foreach}
    - +{*
    @@ -32,25 +39,20 @@ informed when this state is reached.{/i18n}

    {/foreach} {/if} +{if $aGroups}

    {i18n}Groups{/i18n}

    {entity_checkboxes entities=$aGroups name="fGroupIds" multiple="true" selected=$aInformed.group assign=aBoxes} {foreach from=$aBoxes item=sBox} {$sBox}
    {/foreach} +{/if} -{* -

    {i18n}Users{/i18n}

    -{entity_checkboxes entities=$aUsers name="fUserIds" multiple="true" selected=$aInformed.user assign=aBoxes} -{foreach from=$aBoxes item=sBox} -{$sBox}
    -{/foreach} - - -
    -*} +{if (empty($aGroups) && empty($aRoles))} +

    {i18n}No groups or roles are defined in the DMS.{/i18n}

    +{/if} - +*} {*

    {i18n}Assigned Permissions{/i18n}

    @@ -63,9 +65,13 @@ transition can be accomplished.{/i18n}

    {i18n}Transitions{/i18n} -{if $aTransitionsTo} +

    {i18n}Transitions are how documents move from one +state to another. Typically, most transitions can only be performed by people +with a specific role (e.g. Manager) or part of a specific group +(e.g. Marketing Department).{/i18n}

    +{if $aTransitionsTo}

    {i18n}Transitions to this state{/i18n}

    {if (!empty($aTransitionsTo))}
      @@ -76,11 +82,11 @@ title="Transition {$oTransition->getId()}">{$oTransition->getName()|escape} {/foreach}
    -{else} -{i18n}No transitions lead to this state.{/i18n} -{/if} {/if} +{else} +

    {i18n}No transitions lead to this state.{/i18n}

    +{/if}

    {i18n}Transitions from this state{/i18n}

    @@ -89,12 +95,12 @@ title="Transition {if (!empty($aTransitions))} -{entity_checkboxes entities=$aTransitions name="fTransitionIds" multiple="true" selected=$aTransitionsSelected} +{entity_checkboxes entities=$aTransitions name="fTransitionIds" multiple="true" selected=$aTransitionsSelected separator="
    "}
    {else} -{i18n}No transitions defined.{/i18n} +

    {i18n}No transitions have been defined for this workflow.{/i18n}

    {/if}
    @@ -102,6 +108,8 @@ title="Transition + +{if (!empty($aActions))}
    Actions allowed @@ -110,7 +118,6 @@ title="Transition -{if (!empty($aActions))}
      {entity_checkboxes name="fActions" entities=$aActions idmethod="getName" method="getDisplayName" assign="aCheckboxes" selected="$aActionsSelected"} {foreach from=$aCheckboxes item=sCheckbox} @@ -120,9 +127,11 @@ title="Transition
      -{else} -No actions defined. -{/if}
    +{else} +

    No actions are controlled by this workflow, so all actions are available when +documents are in this state.

    +{/if} + diff --git a/templates/ktcore/workflow/editWorkflow.smarty b/templates/ktcore/workflow/editWorkflow.smarty index 6271915..6ec95a5 100644 --- a/templates/ktcore/workflow/editWorkflow.smarty +++ b/templates/ktcore/workflow/editWorkflow.smarty @@ -1,6 +1,6 @@ -

    {i18n}Workflow{/i18n}: {$oWorkflow->getName()|escape}

    - +{$context->oPage->requireCSSResource('resources/css/workflow-admin.css')} +

    {i18n}Workflow Overview{/i18n}: {$oWorkflow->getName()|escape}

    @@ -18,98 +18,34 @@
    -

    States

    -

    FIXME insert intelligent help.

    -
    -
    -{i18n}Create a new state{/i18n} - - - - -{foreach item=oWidget from=$add_state_fields} - {$oWidget->render()} -{/foreach} - -
    - -
    -
    -
    - -{if $aStates} -

    {i18n}Existing states{/i18n}

    -

    {i18n}Select a state to update its properties.{/i18n}

    - -{/if} - - - - -{* check that there are states, and, if not, don't show transitions *} -{if $aStates} - -

    {i18n}Transitions{/i18n}

    - -

    FIXME insert intelligent help.

    - -
    -
    -{i18n}Create a new transition{/i18n} - - - - -{foreach item=oWidget from=$add_transition_fields} - {$oWidget->render()} -{/foreach} - -
    - -
    -
    -
    - - -{if $aTransitions} -

    {i18n}Existing transitions{/i18n}

    - -
      -{foreach from=$aTransitions item=oTransition} -
    • {$oTransition->getName()|escape}
    • +

      {i18n}This page allows you to get a quick overview of the +workflow. To modify items, either select them from the overview below, +or use the "Workflow" menu on the left to create new ones.{/i18n}

      + +{if (empty($aStates))} +

      This workflow does not define any states. Please use the +Workflow menu (on the left) to create new states.

      +{else} +
        +{foreach item=oState from=$aStates} +
      • State: {$oState->getName()} +
          +
        • {i18n}Notified groups & roles:{/i18n} + {$context->getNotificationStringForState($oState)} +
        • +
        • {i18n}Actions available: {/i18n} + {$context->getActionStringForState($oState)} +
        • + +
        • {i18n}Transitions available: {/i18n} + {$context->getTransitionFromStringForState($oState)} +
        • + +
        • {i18n}Transitions to this state: {/i18n} + {$context->getTransitionToStringForState($oState)} +
        • +
        +
      • {/foreach}
      -{/if} - -{/if} - - - -
      -
      -{i18n}Actions controlled{/i18n} - -

      FIXME be helpful

      - - - - -
        -{entity_checkboxes name="fActions" entities=$aActions idmethod="getName" method="getDisplayName" assign="aCheckboxes" selected="$aActionsSelected"} -{foreach from=$aCheckboxes item=sCheckbox} -
      • {$sCheckbox}
      • -{/foreach} -
      -
      - -
      -
      -
      +{/if} \ No newline at end of file diff --git a/templates/ktcore/workflow/listWorkflows.smarty b/templates/ktcore/workflow/listWorkflows.smarty index 760b95b..b1608d4 100644 --- a/templates/ktcore/workflow/listWorkflows.smarty +++ b/templates/ktcore/workflow/listWorkflows.smarty @@ -1,4 +1,9 @@ -

      {i18n}Workflow{/i18n}

      +

      {i18n}Workflows{/i18n}

      + +

      {i18n}Workflow is a description of a document's lifecycle. It is made up of +workflow states, which describe where in the lifecycle the document is, +and workflow transitions, which describe the next steps within the +lifecycle of the document.{/i18n}

      diff --git a/templates/ktcore/workflow/manageActions.smarty b/templates/ktcore/workflow/manageActions.smarty new file mode 100644 index 0000000..59d4458 --- /dev/null +++ b/templates/ktcore/workflow/manageActions.smarty @@ -0,0 +1,73 @@ +{$context->oPage->requireCSSResource('resources/css/workflow-admin.css')} +

      {i18n}Manage Actions{/i18n}

      + +

      {i18n}An important part of workflow is controlling which +actions are available to users at various stages. For example, it may be +necessary to prevent the "Edit Metadata" action from being used when a document +is "published". Doing this is a two step process: first, you need to specify +that "Edit Metadata" is an action you wish to control within this workflow; second, +you need to specify that the action is not to be made available +when documents are in the "published" state.{/i18n}

      + + +
      {i18n}Specify Controlled Actions{/i18n} +

      {i18n}Select the actions you want this workflow +to control from the list below. Actions you do not specify will be available no +matter what the state of the document.{/i18n}

      + + + + + +{entity_checkboxes name="fActions" entities="$aActions" idmethod="getName" method="getDisplayName" assign="aCheckboxes" selected="$aActionsSelected" separator="
      "} +{foreach from=$aCheckboxes item=sCheckbox} +{$sCheckbox} +{/foreach} + +
      + +
      + +
      + + +

      Assign Actions to States

      + +

      The table below lists the actions you have specified +as controlled by this workflow, and all the states within the workflow. From here +you can assign those actions to the various states in this workflow.

      + +{if (empty($aActionsSelected))} +

      {i18n}No actions are controlled by this workflow. All actions +will be available at all states.{/i18n}

      +{else} +
      + + + + + + + {foreach from=$aActions item=oAction} + + {/foreach} + + + +{foreach item=oState from=$workflow_info.states} + + + {foreach item=oAction from=$aActions} + + {/foreach} + +{/foreach} + +
       {$oAction->getDisplayName()}
      {$oState->getName()}actionAvailable($oAction, $oState))}checked="true"{/if}/>
      + +
      + +
      +
      +{/if} + diff --git a/templates/ktcore/workflow/manageStates.smarty b/templates/ktcore/workflow/manageStates.smarty new file mode 100644 index 0000000..b95af0e --- /dev/null +++ b/templates/ktcore/workflow/manageStates.smarty @@ -0,0 +1,58 @@ +{$context->oPage->requireCSSResource('resources/css/workflow-admin.css')} +

      {i18n}Manage States{/i18n}

      + +

      As documents move through their lifecycle, they +are placed in certain states. For example, an invoice +which has been mailed might be in the "Pending" state after +the "sent" transition has been performed by a user.

      + +
      +
      +{i18n}Create a new state{/i18n} + +

      Please note that additional configuration is +possible on states beyond what is specified here (e.g. which users to notify +about the document, etc). Please edit the state +to access and modify these other properties.

      + + + + +{* Standard Form *} + +{foreach item=oWidget from=$add_fields} + {$oWidget->render()} +{/foreach} + +
      + +
      +
      +
      + +{if (empty($workflow_info.states))} +

      This workflow does not define any states.

      +{else} + +{/if} \ No newline at end of file diff --git a/templates/ktcore/workflow/manageTransitions.smarty b/templates/ktcore/workflow/manageTransitions.smarty new file mode 100644 index 0000000..d74dc39 --- /dev/null +++ b/templates/ktcore/workflow/manageTransitions.smarty @@ -0,0 +1,74 @@ +

      {i18n}Manage Transitions{/i18n}

      + +

      {i18n}Transitions are what drive the workflow of documents. +Each step that needs to be followed in the document's lifecycle could +map to a transition, and can be allowed or denied by a combination +of roles, permissions and groups.{/i18n}

      + +

      {i18n}Use the form below to create a new Transition, and +assign or edit existing transitions using the table below.{/i18n}

      + +
      +
      +{i18n}Create a new state{/i18n} + + + + +{* Standard Form *} + +{foreach item=oWidget from=$add_fields} + {$oWidget->render()} +{/foreach} + +
      + +
      +
      +
      + +

      {i18n}Transition Availability{/i18n}

      + +

      Click on any transition below to edit it directly, +or use the checkboxes to assign which states the transition is available from.

      + +
      + + + + + + + + {foreach item=oState from=$workflow_info.states} + + {/foreach} + + + + {foreach item=oTransition from=$workflow_info.transitions} + + + {foreach item=oState from=$workflow_info.states} + + {/foreach} + + {/foreach} + +
      +   + + {$oState->getName()} +
      + {$oTransition->getName()} + + {if ($oState->getId() != $oTransition->getTargetStateId())} + transitionAvailable($oTransition, $oState))}checked="true"{/if}> + {else}—{/if} +
      + +
      + +
      + + \ No newline at end of file