Minor tweaks t othe onboarding page. (#430)

* * Display the instructions_for_user directly on the home page (no redirects to alternate pages)
* Moved the onboarding view above the tabs on the home page.
* Added a "times_executed_by_user" script - not sure if we should keep it, but maybe handy.
* Assure that the display_name for the user is returned consistently (it was not being returned by the get_current_user function).

With @jbirddog

* remove pointless comment.
This commit is contained in:
Dan Funk 2023-08-03 15:08:25 -04:00 committed by GitHub
parent 3f6fb4d9f5
commit b446aad184
9 changed files with 72 additions and 8 deletions

View File

@ -27,12 +27,12 @@ class UserModel(SpiffworkflowBaseDBModel):
id: int = db.Column(db.Integer, primary_key=True)
username: str = db.Column(db.String(255), nullable=False, unique=True)
email = db.Column(db.String(255), index=True)
email: str = db.Column(db.String(255), index=True)
service = db.Column(db.String(255), nullable=False, unique=False, index=True) # not 'openid' -- google, aws
service_id = db.Column(db.String(255), nullable=False, unique=False, index=True)
display_name = db.Column(db.String(255))
display_name: str = db.Column(db.String(255))
tenant_specific_field_1: str | None = db.Column(db.String(255))
tenant_specific_field_2: str | None = db.Column(db.String(255))
tenant_specific_field_3: str | None = db.Column(db.String(255))

View File

@ -4,7 +4,10 @@ from contextlib import suppress
from flask import make_response
from flask.wrappers import Response
from spiffworkflow_backend import db
from spiffworkflow_backend.models.task import TaskModel
from spiffworkflow_backend.routes.process_instances_controller import _process_instance_start
from spiffworkflow_backend.services.jinja_service import JinjaService
def get_onboarding() -> Response:
@ -21,7 +24,14 @@ def get_onboarding() -> Response:
result = {
"type": "user_input_required",
"process_instance_id": process_instance.id,
"task_id": process_instance.active_human_tasks[0].task_id,
}
task = processor.next_task()
db.session.flush()
if task:
task_model: TaskModel | None = TaskModel.query.filter_by(guid=str(task.id),
process_instance_id=process_instance.id).first()
result['task_id'] = task_model.guid
result['instructions'] = JinjaService.render_instructions_for_end_user(task_model)
return make_response(result, 200)

View File

@ -0,0 +1,22 @@
from typing import Any
from spiffworkflow_backend.models.script_attributes_context import ScriptAttributesContext
from spiffworkflow_backend.scripts.script import Script
from spiffworkflow_backend.services.process_instance_service import ProcessInstanceService
class TimesExecutedByUser(Script):
@staticmethod
def requires_privileged_permissions() -> bool:
"""We have deemed this function safe to run without elevated permissions."""
return False
def get_description(self) -> str:
return """Returns boolean to indicate if the user has started an instance of the current process model."""
def run(self, script_attributes_context: ScriptAttributesContext, *_args: Any, **kwargs: Any) -> Any:
process_model_identifer = script_attributes_context.process_model_identifier
if process_model_identifer is not None:
return ProcessInstanceService.times_executed_by_user(process_model_identifer)
else:
return False

View File

@ -57,6 +57,18 @@ class ProcessInstanceService:
)
return started_instance is not None
def times_executed_by_user(process_model_identifier: str) -> bool:
total = (
db.session.query(ProcessInstanceModel)
.filter(
ProcessInstanceModel.process_model_identifier == process_model_identifier
)
.count()
)
return total
@staticmethod
def next_start_event_configuration(process_instance_model: ProcessInstanceModel) -> StartConfiguration:
try:

View File

@ -17,6 +17,7 @@ class TestGetCurrentUser(BaseTest):
) -> None:
testuser1 = self.find_or_create_user("testuser1")
testuser1.tenant_specific_field_1 = "456"
testuser1.display_name = "Test User NUMBER ONE!"
db.session.add(testuser1)
db.session.commit()
@ -35,4 +36,5 @@ class TestGetCurrentUser(BaseTest):
)
assert result["username"] == "testuser1"
assert result["tenant_specific_field_1"] == "456"
assert result["display_name"] == "Test User NUMBER ONE!"
json.dumps(result)

View File

@ -91,3 +91,7 @@ div.cds--tag svg {
vertical-align: middle;
display: inline-block;
}
div.onboarding {
margin-bottom: 2rem;
}

View File

@ -15,6 +15,7 @@ export interface Onboarding {
value?: string;
process_instance_id?: string;
task_id?: string;
instructions: string;
}
export interface ProcessData {

View File

@ -49,9 +49,9 @@ export default function HomePageRoutes() {
return (
<div className="fixed-width-container">
<OnboardingView />
{renderTabs()}
<Routes>
<Route path="/" element={<OnboardingView />} />
<Route path="my-tasks" element={<MyTasks />} />
<Route path=":process_instance_id/:task_id" element={<TaskShow />} />
<Route path="grouped" element={<InProgressInstances />} />

View File

@ -1,5 +1,6 @@
import { useEffect, useState } from 'react';
import React, { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import MDEditor from '@uiw/react-md-editor';
import HttpService from '../services/HttpService';
import InProgressInstances from './InProgressInstances';
import { Onboarding } from '../interfaces';
@ -18,11 +19,23 @@ export default function OnboardingView() {
}, [setOnboarding]);
const onboardingElement = () => {
if (onboarding) {
if (onboarding && onboarding.instructions.length > 0) {
return (
<MDEditor.Markdown
className="onboarding"
linkTarget="_blank"
source={onboarding.instructions}
/>
);
/*
if (onboarding.type === 'default_view') {
if (onboarding.value === 'my_tasks') {
return <MyTasks />;
}
} else if (
onboarding.type === 'user_input_required'
) {
console.log("onboarding");
} else if (
onboarding.type === 'user_input_required' &&
onboarding.process_instance_id &&
@ -32,9 +45,9 @@ export default function OnboardingView() {
`/tasks/${onboarding.process_instance_id}/${onboarding.task_id}`
);
}
*/
}
return <InProgressInstances />;
return null;
};
return onboardingElement();