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:
parent
4b771ac706
commit
26cedac42b
|
@ -27,12 +27,12 @@ class UserModel(SpiffworkflowBaseDBModel):
|
||||||
|
|
||||||
id: int = db.Column(db.Integer, primary_key=True)
|
id: int = db.Column(db.Integer, primary_key=True)
|
||||||
username: str = db.Column(db.String(255), nullable=False, unique=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 = 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)
|
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_1: str | None = db.Column(db.String(255))
|
||||||
tenant_specific_field_2: 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))
|
tenant_specific_field_3: str | None = db.Column(db.String(255))
|
||||||
|
|
|
@ -4,7 +4,10 @@ from contextlib import suppress
|
||||||
from flask import make_response
|
from flask import make_response
|
||||||
from flask.wrappers import 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.routes.process_instances_controller import _process_instance_start
|
||||||
|
from spiffworkflow_backend.services.jinja_service import JinjaService
|
||||||
|
|
||||||
|
|
||||||
def get_onboarding() -> Response:
|
def get_onboarding() -> Response:
|
||||||
|
@ -21,7 +24,14 @@ def get_onboarding() -> Response:
|
||||||
result = {
|
result = {
|
||||||
"type": "user_input_required",
|
"type": "user_input_required",
|
||||||
"process_instance_id": process_instance.id,
|
"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)
|
return make_response(result, 200)
|
||||||
|
|
|
@ -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
|
|
@ -57,6 +57,18 @@ class ProcessInstanceService:
|
||||||
)
|
)
|
||||||
return started_instance is not None
|
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
|
@staticmethod
|
||||||
def next_start_event_configuration(process_instance_model: ProcessInstanceModel) -> StartConfiguration:
|
def next_start_event_configuration(process_instance_model: ProcessInstanceModel) -> StartConfiguration:
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -17,6 +17,7 @@ class TestGetCurrentUser(BaseTest):
|
||||||
) -> None:
|
) -> None:
|
||||||
testuser1 = self.find_or_create_user("testuser1")
|
testuser1 = self.find_or_create_user("testuser1")
|
||||||
testuser1.tenant_specific_field_1 = "456"
|
testuser1.tenant_specific_field_1 = "456"
|
||||||
|
testuser1.display_name = "Test User NUMBER ONE!"
|
||||||
db.session.add(testuser1)
|
db.session.add(testuser1)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
@ -35,4 +36,5 @@ class TestGetCurrentUser(BaseTest):
|
||||||
)
|
)
|
||||||
assert result["username"] == "testuser1"
|
assert result["username"] == "testuser1"
|
||||||
assert result["tenant_specific_field_1"] == "456"
|
assert result["tenant_specific_field_1"] == "456"
|
||||||
|
assert result["display_name"] == "Test User NUMBER ONE!"
|
||||||
json.dumps(result)
|
json.dumps(result)
|
||||||
|
|
|
@ -91,3 +91,7 @@ div.cds--tag svg {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.onboarding {
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
|
@ -15,6 +15,7 @@ export interface Onboarding {
|
||||||
value?: string;
|
value?: string;
|
||||||
process_instance_id?: string;
|
process_instance_id?: string;
|
||||||
task_id?: string;
|
task_id?: string;
|
||||||
|
instructions: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProcessData {
|
export interface ProcessData {
|
||||||
|
|
|
@ -49,9 +49,9 @@ export default function HomePageRoutes() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed-width-container">
|
<div className="fixed-width-container">
|
||||||
|
<OnboardingView />
|
||||||
{renderTabs()}
|
{renderTabs()}
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<OnboardingView />} />
|
|
||||||
<Route path="my-tasks" element={<MyTasks />} />
|
<Route path="my-tasks" element={<MyTasks />} />
|
||||||
<Route path=":process_instance_id/:task_id" element={<TaskShow />} />
|
<Route path=":process_instance_id/:task_id" element={<TaskShow />} />
|
||||||
<Route path="grouped" element={<InProgressInstances />} />
|
<Route path="grouped" element={<InProgressInstances />} />
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import MDEditor from '@uiw/react-md-editor';
|
||||||
import HttpService from '../services/HttpService';
|
import HttpService from '../services/HttpService';
|
||||||
import InProgressInstances from './InProgressInstances';
|
import InProgressInstances from './InProgressInstances';
|
||||||
import { Onboarding } from '../interfaces';
|
import { Onboarding } from '../interfaces';
|
||||||
|
@ -18,11 +19,23 @@ export default function OnboardingView() {
|
||||||
}, [setOnboarding]);
|
}, [setOnboarding]);
|
||||||
|
|
||||||
const onboardingElement = () => {
|
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.type === 'default_view') {
|
||||||
if (onboarding.value === 'my_tasks') {
|
if (onboarding.value === 'my_tasks') {
|
||||||
return <MyTasks />;
|
return <MyTasks />;
|
||||||
}
|
}
|
||||||
|
} else if (
|
||||||
|
onboarding.type === 'user_input_required'
|
||||||
|
) {
|
||||||
|
console.log("onboarding");
|
||||||
} else if (
|
} else if (
|
||||||
onboarding.type === 'user_input_required' &&
|
onboarding.type === 'user_input_required' &&
|
||||||
onboarding.process_instance_id &&
|
onboarding.process_instance_id &&
|
||||||
|
@ -32,9 +45,9 @@ export default function OnboardingView() {
|
||||||
`/tasks/${onboarding.process_instance_id}/${onboarding.task_id}`
|
`/tasks/${onboarding.process_instance_id}/${onboarding.task_id}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
return <InProgressInstances />;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return onboardingElement();
|
return onboardingElement();
|
||||||
|
|
Loading…
Reference in New Issue