diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000000000000000000000000000000000..cad7657dfa543e02eca53f1ecc7545c92bc0a550 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "cmake.configureOnOpen": false +} \ No newline at end of file diff --git a/MAC/Deployment/data/StaticMetaData/CableDelays/CS030-CableDelays.conf b/MAC/Deployment/data/StaticMetaData/CableDelays/CS030-CableDelays.conf index 204a334e12b246e4f005a907e37f7efe939fd414..cfc24531fd144ec059c9175a806576c27127163f 100644 --- a/MAC/Deployment/data/StaticMetaData/CableDelays/CS030-CableDelays.conf +++ b/MAC/Deployment/data/StaticMetaData/CableDelays/CS030-CableDelays.conf @@ -16,6 +16,10 @@ # 115m 465.5254 # 130m 530.6981 # +# T25 has 122 meter coax i.s.o. 115 meter. New delay in table added (M.J. Norden, 24-9-2020) +#50 115 465.5254 80 326.9640 115 493.8617 +#51 115 465.5254 80 326.9640 115 493.8617 +# # LBL LBH HBA #RCUnr len delay len delay len delay #----------------------------------------------------------------------- @@ -69,8 +73,8 @@ 47 115 465.5254 80 326.9640 115 465.5254 48 115 465.5254 80 326.9640 115 465.5254 49 115 465.5254 80 326.9640 115 465.5254 -50 115 465.5254 80 326.9640 115 465.5254 -51 115 465.5254 80 326.9640 115 465.5254 +50 115 465.5254 80 326.9640 120 493.8617 +51 115 465.5254 80 326.9640 120 493.8617 52 115 465.5254 115 465.5254 115 465.5254 53 115 465.5254 115 465.5254 115 465.5254 54 80 326.9640 115 465.5254 115 465.5254 diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/Stations.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/Stations.js index 841672888ac6cdbc75d850b1a39442f2752e1f59..7a7a354a7fd5872a6ee6256abba1b92749a22538 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/Stations.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/Stations.js @@ -122,7 +122,7 @@ export default (props) => { custom_stations_options = custom_stations_options.map(i => ({ value: i })); setCustomStationsOptions(custom_stations_options); if (props.onUpdateStations) { - updateSchedulingComp(stationState, [...selected_Stations], missing_StationFieldsErrors, customStations); + updateSchedulingComp(stationState, [...selected_Stations], missing_StationFieldsErrors, custom_stations); } }; diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/ViewSchedulingUnit.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/ViewSchedulingUnit.js index 22914ed8871b0fe0ed58a456c2aa4baa4021b5bd..a76501c5c154cadef3782037eb877ff3db06c865 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/ViewSchedulingUnit.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/ViewSchedulingUnit.js @@ -9,6 +9,7 @@ import PageHeader from '../../layout/components/PageHeader'; import ViewTable from './../../components/ViewTable'; import ScheduleService from '../../services/schedule.service'; import moment from 'moment'; +import _ from 'lodash'; import SchedulingConstraint from './Scheduling.Constraints'; import { Dialog } from 'primereact/dialog'; import TaskStatusLogs from '../Task/state_logs'; @@ -120,12 +121,12 @@ class ViewSchedulingUnit extends Component{ task.status_logs = task.tasktype === "Blueprint"?subtaskComponent(task):""; return task; }); - const targetObservation = tasks.find(task => task.name === 'Target Observation'); + const targetObservation = _.find(tasks, (task)=> {return task.template.type_value==='observation' && task.tasktype.toLowerCase()===schedule_type && task.specifications_doc.station_groups}); this.setState({ scheduleunit : schedulingUnit, schedule_unit_task : tasks, isLoading: false, - stationGroup: targetObservation.specifications_doc.station_groups + stationGroup: targetObservation?targetObservation.specifications_doc.station_groups:[] }, this.getAllStations); }); } else { @@ -139,9 +140,9 @@ class ViewSchedulingUnit extends Component{ getScheduleUnitTasks(type, scheduleunit){ if(type === 'draft') - return ScheduleService.getTasksBySchedulingUnit(scheduleunit.id); + return ScheduleService.getTasksBySchedulingUnit(scheduleunit.id, true); else - return ScheduleService.getTaskBlueprintsBySchedulingUnit(scheduleunit); + return ScheduleService.getTaskBlueprintsBySchedulingUnit(scheduleunit, true); } getScheduleUnit(type, id){ if(type === 'draft') diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/create.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/create.js index 805787316649f94e265385af3e200bd9a8c73d20..f70b3eb5b38d6797bc9b578dd2e660c9a8379b54 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/create.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/create.js @@ -121,8 +121,7 @@ export class SchedulingUnitCreate extends Component { */ async changeStrategy (strategyId) { const observStrategy = _.find(this.observStrategies, {'id': strategyId}); - const station_group = observStrategy.template.tasks['Target Observation'].specifications_doc.station_groups; - this.setState({ stationGroup: station_group }); + let station_group = []; const tasks = observStrategy.template.tasks; let paramsOutput = {}; let schema = { type: 'object', additionalProperties: false, @@ -138,6 +137,9 @@ export class SchedulingUnitCreate extends Component { const taskTemplate = _.find(this.taskTemplates, {'name': task['specifications_template']}); schema['$id'] = taskTemplate.schema['$id']; schema['$schema'] = taskTemplate.schema['$schema']; + if (taskTemplate.type_value==='observation' && task.specifications_doc.station_groups) { + station_group = task.specifications_doc.station_groups; + } let index = 0; for (const param of observStrategy.template.parameters) { if (param.refs[0].indexOf(`/tasks/${taskName}`) > 0) { @@ -174,7 +176,7 @@ export class SchedulingUnitCreate extends Component { } } - this.setState({observStrategy: observStrategy, paramsSchema: schema, paramsOutput: paramsOutput}); + this.setState({observStrategy: observStrategy, paramsSchema: schema, paramsOutput: paramsOutput, stationGroup: station_group}); // Function called to clear the JSON Editor fields and reload with new schema if (this.state.editorFunction) { @@ -345,6 +347,12 @@ export class SchedulingUnitCreate extends Component { observStrategy.template.parameters.forEach(async(param, index) => { $refs.set(observStrategy.template.parameters[index]['refs'][0], this.state.paramsOutput['param_' + index]); }); + for (const taskName in observStrategy.template.tasks) { + let task = observStrategy.template.tasks[taskName]; + if (task.specifications_doc.station_groups) { + task.specifications_doc.station_groups = station_groups; + } + } const const_strategy = {scheduling_constraints_doc: constStrategy, id: this.constraintTemplates[0].id, constraint: this.constraintTemplates[0]}; const schedulingUnit = await ScheduleService.saveSUDraftFromObservStrategy(observStrategy, this.state.schedulingUnit, const_strategy, station_groups); if (schedulingUnit) { diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/edit.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/edit.js index d3060f0f30d53126e4b4d95596323c40e99a879f..f2f56627824593d0f270148148f2e718fb2d41ff 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/edit.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/edit.js @@ -130,6 +130,9 @@ export class EditSchedulingUnit extends Component { } index++; } + if (taskTemplate.type_value==='observation' && task.specifications_doc.station_groups) { + tasksToUpdate[taskName] = taskName; + } } this.setState({observStrategy: observStrategy, paramsSchema: schema, paramsOutput: paramsOutput, tasksToUpdate: tasksToUpdate}); @@ -161,9 +164,9 @@ export class EditSchedulingUnit extends Component { observStrategyVisible: responses[4].observation_strategy_template_id?true:false }); if (responses[4].observation_strategy_template_id) { this.changeStrategy(responses[4].observation_strategy_template_id); - const targetObservation = responses[5].data.results.find(task => task.name === 'Target Observation'); + const targetObservation = responses[5].data.results.find(task => {return task.specifications_doc.station_groups?true:false}); this.setState({ - stationGroup: targetObservation.specifications_doc.station_groups + stationGroup: targetObservation?targetObservation.specifications_doc.station_groups:[] }); } if (this.state.schedulingUnit.project) { diff --git a/SAS/TMSS/frontend/tmss_webapp/src/services/schedule.service.js b/SAS/TMSS/frontend/tmss_webapp/src/services/schedule.service.js index 6c7570bb5988cac32bb82e12a79eb8a48940ca3f..1ace4022edceedeffc7a6916b1749edaf81cc4fa 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/services/schedule.service.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/services/schedule.service.js @@ -91,7 +91,7 @@ const ScheduleService = { } return taskblueprintsList; }, - getTasksBySchedulingUnit: async function(id){ + getTasksBySchedulingUnit: async function(id, loadTemplate){ let scheduletasklist=[]; // let taskblueprints = []; // Common keys for Task and Blueprint @@ -119,6 +119,9 @@ const ScheduleService = { scheduletask.duration = moment.utc((scheduletask.duration || 0)*1000).format('HH:mm:ss'); scheduletask.relative_start_time = moment.utc(scheduletask.relative_start_time*1000).format('HH:mm:ss'); scheduletask.relative_stop_time = moment.utc(scheduletask.relative_stop_time*1000).format('HH:mm:ss'); + if (loadTemplate) { + scheduletask.template = await TaskService.getTaskTemplate(task.specifications_template_id); + } //Fetch blueprint details for Task Draft const draftBlueprints = await TaskService.getDraftsTaskBlueprints(task.id); // let filteredblueprints = _.filter(taskblueprints, function(o) { @@ -140,7 +143,9 @@ const ScheduleService = { taskblueprint.duration = moment.utc((taskblueprint.duration || 0)*1000).format('HH:mm:ss'); taskblueprint.relative_start_time = moment.utc(taskblueprint.relative_start_time*1000).format('HH:mm:ss'); taskblueprint.relative_stop_time = moment.utc(taskblueprint.relative_stop_time*1000).format('HH:mm:ss'); - + if (loadTemplate) { + taskblueprint.template = scheduletask.template; + } //Add Blue print details to array scheduletasklist.push(taskblueprint); } @@ -237,7 +242,6 @@ const ScheduleService = { if (schedulingUnit && schedulingUnit.id) { // Update the newly created SU draft requirement_doc with captured parameter values schedulingUnit.requirements_doc = observStrategy.template; - schedulingUnit.requirements_doc.tasks['Target Observation'].specifications_doc.station_groups = station_groups; schedulingUnit.scheduling_constraints_doc = constraint.scheduling_constraints_doc; schedulingUnit.scheduling_constraints_template_id = constraint.id; schedulingUnit.scheduling_constraints_template = constraint.constraint.url; @@ -267,7 +271,7 @@ const ScheduleService = { for (const taskToUpdate in tasksToUpdate) { let task = tasks.find(task => { return task.name === taskToUpdate}); task.specifications_doc = observStrategy.template.tasks[taskToUpdate].specifications_doc; - if (task.name === 'Target Observation') { + if (task.specifications_doc.station_groups) { task.specifications_doc.station_groups = station_groups; } delete task['duration']; diff --git a/SAS/TMSS/src/tmss/urls.py b/SAS/TMSS/src/tmss/urls.py index a97ef0a61de0392f08edcc2f25ab3c7f0f412e3f..feb8e3e3186fc889a9f54b3b901c8d5f4ca58b70 100644 --- a/SAS/TMSS/src/tmss/urls.py +++ b/SAS/TMSS/src/tmss/urls.py @@ -31,7 +31,9 @@ from drf_yasg import openapi from datetime import datetime import os from material.frontend import urls as frontend_urls + from viewflow.flow.viewset import FlowViewSet +from .workflowapp import viewsets as workflow_viewsets # @@ -206,7 +208,21 @@ router.register(r'user', viewsets.UserViewSet) router.register(r'sap', viewsets.SAPViewSet) router.register(r'sip_identifier', viewsets.SIPidentifierViewSet) -# --- +# --- +# QA Workflow steps +viewflow_urlpatterns = [] + +viewflow_router = OptionalSlashRouter() +viewflow_router.APIRootView = TMSSAPIRootView + +viewflow_router.register('scheduling_unit_flow/su', workflow_viewsets.SchedulingUnitFlowViewSet, basename='su') +viewflow_router.register('scheduling_unit_flow/qa_reporting_to', workflow_viewsets.QAReportingTOViewSet, basename='qa_reporting_to') +viewflow_router.register('scheduling_unit_flow/qa_reporting_sos', workflow_viewsets.QAReportingSOSViewSet, basename='qa_reporting_sos') +viewflow_router.register('scheduling_unit_flow/qa_pi_verification', workflow_viewsets.PIVerificationViewSet, basename='qa_pi_verification') +viewflow_router.register('scheduling_unit_flow/qa_decide_acceptance', workflow_viewsets.DecideAcceptanceViewSet, basename='qa_decide_acceptance') +viewflow_router.register('scheduling_unit_flow/qa_scheduling_unit_process', workflow_viewsets.SchedulingUnitProcessViewSet, basename='qa_scheduling_unit_process') + +viewflow_urlpatterns.extend(viewflow_router.urls) urlpatterns.extend(router.urls) @@ -214,12 +230,12 @@ frontend_urlpatterns = [ path("", views.index, name="index") ] - -urlpatterns = [url(r'^api$', RedirectView.as_view(url='/api/')), - url(r'^api/', include(urlpatterns)), url(r'^oidc$', - RedirectView.as_view(url='/oidc/')), +urlpatterns = [ url(r'^api$', RedirectView.as_view(url='/api/')), + url(r'^api/', include(urlpatterns)), + url(r'^oidc$', RedirectView.as_view(url='/oidc/')), url(r'^oidc/', include('mozilla_django_oidc.urls')), url(r'^workflow$', RedirectView.as_view(url='/workflow/', permanent=False)), + url(r'^workflow_api/', include(viewflow_urlpatterns)), url(r'', include(frontend_urls)), url(r'^.*', include(frontend_urlpatterns)), ] diff --git a/SAS/TMSS/src/tmss/workflowapp/CMakeLists.txt b/SAS/TMSS/src/tmss/workflowapp/CMakeLists.txt index 94b72e83e35a77ab9b16f84b7647f8ab0c8af94a..e7c3171661a6fd3927e6b4214251c21f0240d0b1 100644 --- a/SAS/TMSS/src/tmss/workflowapp/CMakeLists.txt +++ b/SAS/TMSS/src/tmss/workflowapp/CMakeLists.txt @@ -15,3 +15,6 @@ add_subdirectory(migrations) add_subdirectory(models) add_subdirectory(flows) add_subdirectory(viewsets) +add_subdirectory(forms) +add_subdirectory(templates) +add_subdirectory(serializers) diff --git a/SAS/TMSS/src/tmss/workflowapp/flows/CMakeLists.txt b/SAS/TMSS/src/tmss/workflowapp/flows/CMakeLists.txt index 769f922e4781a912f1c0488c3655f6ab61363d3a..ba35dcf6abd1341333f5da54b43b2977805ef628 100644 --- a/SAS/TMSS/src/tmss/workflowapp/flows/CMakeLists.txt +++ b/SAS/TMSS/src/tmss/workflowapp/flows/CMakeLists.txt @@ -4,7 +4,7 @@ include(PythonInstall) set(_py_files __init__.py helloworldflow.py - schedulingunitdemoflow.py + schedulingunitflow.py ) python_install(${_py_files} diff --git a/SAS/TMSS/src/tmss/workflowapp/flows/__init__.py b/SAS/TMSS/src/tmss/workflowapp/flows/__init__.py index 45516795a25730483ebfa40c1fbdb5f533df8ebe..a0ae3713747c0b28c5595736d06f4bcb800da5b5 100644 --- a/SAS/TMSS/src/tmss/workflowapp/flows/__init__.py +++ b/SAS/TMSS/src/tmss/workflowapp/flows/__init__.py @@ -1,2 +1,2 @@ from .helloworldflow import * -from .schedulingunitdemoflow import * \ No newline at end of file +from .schedulingunitflow import * \ No newline at end of file diff --git a/SAS/TMSS/src/tmss/workflowapp/flows/schedulingunitdemoflow.py b/SAS/TMSS/src/tmss/workflowapp/flows/schedulingunitflow.py similarity index 57% rename from SAS/TMSS/src/tmss/workflowapp/flows/schedulingunitdemoflow.py rename to SAS/TMSS/src/tmss/workflowapp/flows/schedulingunitflow.py index 0a2882d7a4550ef3ff8e60b190c4074f60356795..8d01c51a15bc840bdb775acce1297938234a1611 100644 --- a/SAS/TMSS/src/tmss/workflowapp/flows/schedulingunitdemoflow.py +++ b/SAS/TMSS/src/tmss/workflowapp/flows/schedulingunitflow.py @@ -9,6 +9,7 @@ from viewflow.flow.nodes import Signal from viewflow import mixins from .. import models +from .. import viewsets from viewflow import frontend, ThisObject from viewflow.activation import STATUS @@ -26,7 +27,7 @@ class ConditionActivation(FuncActivation): return activation class Condition(Signal): - #task_type = "HUMAN" # makes it show up in the unassigned task lists + task_type = "HUMAN" # makes it show up in the unassigned task lists activation_class = ConditionActivation def __init__(self, condition_check, signal, sender=None, task_loader=None, **kwargs): @@ -65,55 +66,14 @@ class Condition(Signal): super(Condition, self).ready() @frontend.register -class SchedulingUnitDemoFlow(Flow): - process_class = models.SchedulingUnitDemoProcess - - # 0. Start on SU instantiation - # 1. To be Manually scheduled? -> Go to 1a - # 1a. Present view to manually schedule. - # 2. Wait on signal SU got finished/error/cancelled (might have already!!) -> - # - Wait for assignment to RO user - # View: - Present any quality plots - # - Present any error info - # - Present fixing options - # - Present choice to fix & redo, discard, or continue. - # Continue: - # View: - Present any quality plots - # - Present any error info - # - Submit quality report/score - # - Submit recommendation - # 3. - Assign ticket to Contact Author - # - Present quality plots to user - # - Present quality report/score, and recommendation - # - Submit acceptance & report - # 4. - Assign ticket to owner in step 2. - # - Present quality report/score, and recommendation - # - Present acceptance & report - # - Present choice to ingest or discard. - # Ingest: - # Set ingestable flag on SU. - # Discard: - Cancel SU (triggering garbage collection - # - # Fix & Redo: - # - Wait for user to confirm SU is fixed - # - Go to 2 - # - - # Consider adding to any/all views: - # - Present any opened JIRA tickets - # - Present opportunity to open JIRA ticket - # Note that previously submitted info can be found by clicking through the task. So - # we only need to show whats nominally needed. - # Note that orthogonally to the above flow: - # - Users need to be informed tasks are assigned to them (e-mail?) - # - Users already have an overview in viewflow of tickets assigned to them - # - We likely want to control what e-mails are sent. +class SchedulingUnitFlow(Flow): + process_class = models.SchedulingUnitProcess start = ( flow.StartSignal( post_save, this.on_save_can_start, - sender=models.SchedulingUnitDemo + sender=models.SchedulingUnit ).Next(this.wait_schedulable) ) @@ -121,39 +81,77 @@ class SchedulingUnitDemoFlow(Flow): Condition( this.check_condition, post_save, - sender=models.SchedulingUnitDemo, + sender=models.SchedulingUnit, task_loader=this.get_scheduling_unit_task ) - .Next(this.form) + .Next(this.qa_reporting_to) ) - form = ( + #QA Reporting (TO) + qa_reporting_to = ( flow.View( - UpdateProcessView, - fields=["text"] + viewsets.QAReportingTOView, + task_description='QA Reporting (TO)' ).Permission( auto_create=True - ).Next(this.approve) + ).Next(this.check_operator_accept) + ) + + #Quality Acceptable + check_operator_accept = ( + flow.If(lambda activation: activation.process.qa_reporting_to.operator_accept) + .Then(this.qa_reporting_sos) + .Else(this.mark_sub) ) - approve = ( + #QA Reporting (SOS) + qa_reporting_sos = ( flow.View( - UpdateProcessView, - fields=["approved"] + viewsets.QAReportingSOSView, + task_description='QA Reporting (SOS)' ).Permission( auto_create=True - ).Next(this.check_approve) + ).Next(this.check_sos_accept_show_pi) + ) + + #Quality Acceptable + check_sos_accept_show_pi = ( + flow.If(lambda activation: activation.process.qa_reporting_sos.sos_accept_show_pi) + .Then(this.pi_verification) + .Else(this.mark_sub) ) - check_approve = ( - flow.If(lambda activation: activation.process.approved) - .Then(this.send) - .Else(this.end) + #PI Verification + pi_verification = ( + flow.View( + viewsets.PIVerificationView, + task_description='PI Verification' + ).Permission( + auto_create=True + ).Next(this.decide_acceptance) ) - send = ( + #Decide Acceptance + decide_acceptance = ( + flow.View( + viewsets.DecideAcceptanceView, + task_description='Decide Acceptance' + ).Permission( + auto_create=True + ).Next(this.check_sos_accept_after_pi) + ) + + #Quality Acceptable + check_sos_accept_after_pi = ( + flow.If(lambda activation: activation.process.decide_acceptance.sos_accept_after_pi) + .Then(this.mark_sub) + .Else(this.mark_sub) + ) + + #Mark SUB Successful/failed + mark_sub = ( flow.Handler( - this.send_hello_world_request + this.do_mark_sub ).Next(this.end) ) @@ -164,14 +162,29 @@ class SchedulingUnitDemoFlow(Flow): if created: activation.prepare() activation.process.su = instance + activation.done() print("workflow started") else: print("no workflow started") return activation - def send_hello_world_request(self, activation): - print(activation.process.text) + + def do_mark_sub(self, activation): + + activation.process.can_delete = True + activation.process.results_accepted = ((activation.process.qa_reporting_to is not None and activation.process.qa_reporting_to.operator_accept) + and (activation.process.qa_reporting_sos is not None and activation.process.qa_reporting_sos.sos_accept_show_pi) + and (activation.process.decide_acceptance is not None and activation.process.decide_acceptance.sos_accept_after_pi)) + + print("!!!!!!!!!!!END FLOW!!!!!!!!!!!") + print ("can_delete:") + print (activation.process.can_delete) + print ("results_accepted:") + print (activation.process.results_accepted) + + return activation + def check_condition(self, activation, instance): if instance is None: @@ -183,5 +196,5 @@ class SchedulingUnitDemoFlow(Flow): def get_scheduling_unit_task(self, flow_task, sender, instance, **kwargs): print(kwargs) - process = models.SchedulingUnitDemoProcess.objects.get(su=instance) + process = models.SchedulingUnitProcess.objects.get(su=instance) return Task.objects.get(process=process,flow_task=flow_task) diff --git a/SAS/TMSS/src/tmss/workflowapp/forms/CMakeLists.txt b/SAS/TMSS/src/tmss/workflowapp/forms/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..42b8a34fd53a59e7a7a15885e307a27d4874296a --- /dev/null +++ b/SAS/TMSS/src/tmss/workflowapp/forms/CMakeLists.txt @@ -0,0 +1,10 @@ + +include(PythonInstall) + +set(_py_files + __init__.py + schedulingunitflow.py + ) + +python_install(${_py_files} + DESTINATION lofar/sas/tmss/tmss/workflowapp/forms) diff --git a/SAS/TMSS/src/tmss/workflowapp/forms/__init__.py b/SAS/TMSS/src/tmss/workflowapp/forms/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..bfdfbc84e07beb363937412fd7fb6d5788c684d0 --- /dev/null +++ b/SAS/TMSS/src/tmss/workflowapp/forms/__init__.py @@ -0,0 +1 @@ +from .schedulingunitflow import * \ No newline at end of file diff --git a/SAS/TMSS/src/tmss/workflowapp/forms/schedulingunitflow.py b/SAS/TMSS/src/tmss/workflowapp/forms/schedulingunitflow.py new file mode 100644 index 0000000000000000000000000000000000000000..a967367b38ff77d43ffdf08fb3b30e0f824907ab --- /dev/null +++ b/SAS/TMSS/src/tmss/workflowapp/forms/schedulingunitflow.py @@ -0,0 +1,16 @@ +from django import forms +from material import Layout, Row, Span2 + +from .. import models + + +class QAReportingTO(forms.ModelForm): + layout = Layout( + Row('operator_report'), + Row('operator_accept'), + ) + + class Meta: + model = models.QAReportingTO + fields = ['operator_report','operator_accept'] + #fields = '__all__' \ No newline at end of file diff --git a/SAS/TMSS/src/tmss/workflowapp/migrations/0001_initial.py b/SAS/TMSS/src/tmss/workflowapp/migrations/0001_initial.py index 2e95b97379265e5eb14cfd44e85357218eb63948..1da372c3f5a8ea06e95f13d9861676f8bcdf8636 100644 --- a/SAS/TMSS/src/tmss/workflowapp/migrations/0001_initial.py +++ b/SAS/TMSS/src/tmss/workflowapp/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 3.0.9 on 2020-10-01 12:30 +# Generated by Django 3.0.9 on 2020-11-02 14:31 from django.db import migrations, models import django.db.models.deletion @@ -14,7 +14,39 @@ class Migration(migrations.Migration): operations = [ migrations.CreateModel( - name='SchedulingUnitDemo', + name='DecideAcceptance', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('sos_accept_after_pi', models.BooleanField(default=False)), + ], + ), + migrations.CreateModel( + name='PIVerification', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('pi_report', models.CharField(max_length=150)), + ('pi_accept', models.BooleanField(default=False)), + ], + ), + migrations.CreateModel( + name='QAReportingSOS', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('sos_report', models.CharField(max_length=150)), + ('quality_within_policy', models.CharField(max_length=150)), + ('sos_accept_show_pi', models.BooleanField(default=False)), + ], + ), + migrations.CreateModel( + name='QAReportingTO', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('operator_report', models.CharField(max_length=150)), + ('operator_accept', models.BooleanField(default=False)), + ], + ), + migrations.CreateModel( + name='SchedulingUnit', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(max_length=50)), @@ -35,12 +67,16 @@ class Migration(migrations.Migration): bases=('viewflow.process',), ), migrations.CreateModel( - name='SchedulingUnitDemoProcess', + name='SchedulingUnitProcess', fields=[ ('process_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='viewflow.Process')), - ('text', models.CharField(max_length=150)), - ('approved', models.BooleanField(default=False)), - ('su', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='workflowapp.SchedulingUnitDemo')), + ('can_delete', models.BooleanField(default=False)), + ('results_accepted', models.BooleanField(default=False)), + ('decide_acceptance', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='workflowapp.DecideAcceptance')), + ('pi_verification', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='workflowapp.PIVerification')), + ('qa_reporting_sos', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='workflowapp.QAReportingSOS')), + ('qa_reporting_to', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='workflowapp.QAReportingTO')), + ('su', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='workflowapp.SchedulingUnit')), ], options={ 'abstract': False, diff --git a/SAS/TMSS/src/tmss/workflowapp/models/CMakeLists.txt b/SAS/TMSS/src/tmss/workflowapp/models/CMakeLists.txt index 1c94f0a15d5ade684111945ce5bb79dfe25f7a91..57e7e39aac465b8acf7b209fa3dc901ae4c2076f 100644 --- a/SAS/TMSS/src/tmss/workflowapp/models/CMakeLists.txt +++ b/SAS/TMSS/src/tmss/workflowapp/models/CMakeLists.txt @@ -4,7 +4,7 @@ include(PythonInstall) set(_py_files __init__.py helloworldflow.py - schedulingunitdemoflow.py + schedulingunitflow.py ) python_install(${_py_files} diff --git a/SAS/TMSS/src/tmss/workflowapp/models/__init__.py b/SAS/TMSS/src/tmss/workflowapp/models/__init__.py index 45516795a25730483ebfa40c1fbdb5f533df8ebe..a0ae3713747c0b28c5595736d06f4bcb800da5b5 100644 --- a/SAS/TMSS/src/tmss/workflowapp/models/__init__.py +++ b/SAS/TMSS/src/tmss/workflowapp/models/__init__.py @@ -1,2 +1,2 @@ from .helloworldflow import * -from .schedulingunitdemoflow import * \ No newline at end of file +from .schedulingunitflow import * \ No newline at end of file diff --git a/SAS/TMSS/src/tmss/workflowapp/models/schedulingunitdemoflow.py b/SAS/TMSS/src/tmss/workflowapp/models/schedulingunitdemoflow.py deleted file mode 100644 index b9797a0b12e56ffb6f284da503f43263561522c4..0000000000000000000000000000000000000000 --- a/SAS/TMSS/src/tmss/workflowapp/models/schedulingunitdemoflow.py +++ /dev/null @@ -1,13 +0,0 @@ -# Create your models here. - -from django.db.models import CharField, IntegerField,BooleanField, ForeignKey, CASCADE, Model -from viewflow.models import Process - -class SchedulingUnitDemo(Model): - name = CharField(max_length=50) - state = IntegerField() - -class SchedulingUnitDemoProcess(Process): - text = CharField(max_length=150) - approved = BooleanField(default=False) - su = ForeignKey(SchedulingUnitDemo, blank=True, null=True, on_delete=CASCADE) diff --git a/SAS/TMSS/src/tmss/workflowapp/models/schedulingunitflow.py b/SAS/TMSS/src/tmss/workflowapp/models/schedulingunitflow.py new file mode 100644 index 0000000000000000000000000000000000000000..3e340fbf8c9713fbd37daec0dc977e3d453eb69f --- /dev/null +++ b/SAS/TMSS/src/tmss/workflowapp/models/schedulingunitflow.py @@ -0,0 +1,38 @@ +# Create your models here. + +from django.db.models import CharField, IntegerField,BooleanField, ForeignKey, CASCADE, Model,NullBooleanField +from viewflow.models import Process + +class QAReportingTO(Model): + operator_report = CharField(max_length=150) + operator_accept = BooleanField(default=False) + + +class QAReportingSOS(Model): + sos_report = CharField(max_length=150) + quality_within_policy = CharField(max_length=150) + sos_accept_show_pi = BooleanField(default=False) + + +class PIVerification(Model): + pi_report = CharField(max_length=150) + pi_accept = BooleanField(default=False) + + +class DecideAcceptance(Model): + sos_accept_after_pi = BooleanField(default=False) + + +class SchedulingUnit(Model): + name = CharField(max_length=50) + state = IntegerField() + + +class SchedulingUnitProcess(Process): + su = ForeignKey(SchedulingUnit, blank=True, null=True, on_delete=CASCADE) + qa_reporting_to=ForeignKey(QAReportingTO, blank=True, null=True, on_delete=CASCADE) + qa_reporting_sos=ForeignKey(QAReportingSOS, blank=True, null=True, on_delete=CASCADE) + pi_verification=ForeignKey(PIVerification, blank=True, null=True, on_delete=CASCADE) + decide_acceptance=ForeignKey(DecideAcceptance, blank=True, null=True, on_delete=CASCADE) + can_delete = BooleanField(default=False) + results_accepted = BooleanField(default=False) \ No newline at end of file diff --git a/SAS/TMSS/src/tmss/workflowapp/serializers/CMakeLists.txt b/SAS/TMSS/src/tmss/workflowapp/serializers/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..93e5e84e9ee2e14a5b311ad8f204c7d62920dae0 --- /dev/null +++ b/SAS/TMSS/src/tmss/workflowapp/serializers/CMakeLists.txt @@ -0,0 +1,11 @@ + +include(PythonInstall) + +set(_py_files + __init__.py + schedulingunitflow.py + + ) + +python_install(${_py_files} + DESTINATION lofar/sas/tmss/tmss/workflowapp/serializers) diff --git a/SAS/TMSS/src/tmss/workflowapp/serializers/__init__.py b/SAS/TMSS/src/tmss/workflowapp/serializers/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..bfdfbc84e07beb363937412fd7fb6d5788c684d0 --- /dev/null +++ b/SAS/TMSS/src/tmss/workflowapp/serializers/__init__.py @@ -0,0 +1 @@ +from .schedulingunitflow import * \ No newline at end of file diff --git a/SAS/TMSS/src/tmss/workflowapp/serializers/schedulingunitflow.py b/SAS/TMSS/src/tmss/workflowapp/serializers/schedulingunitflow.py new file mode 100644 index 0000000000000000000000000000000000000000..e29cf3cb9796afcce95e94e63636fe300791f5b0 --- /dev/null +++ b/SAS/TMSS/src/tmss/workflowapp/serializers/schedulingunitflow.py @@ -0,0 +1,41 @@ +from rest_framework.serializers import ModelSerializer +from lofar.sas.tmss.tmss.workflowapp import models + +from django.views import generic +from django.forms.models import modelform_factory + + +from .. import forms + +#View to add a fake Scheduling Unit for the QA Workflow +class SchedulingUnitSerializer(ModelSerializer): + class Meta: + model = models.SchedulingUnit + fields = '__all__' + +#Viewsets and serializers to access intermediate steps of the QA Workflow +#through DRF +class QAReportingTOSerializer(ModelSerializer): + class Meta: + model = models.QAReportingTO + fields = '__all__' + +class QAReportingSOSSerializer(ModelSerializer): + class Meta: + model = models.QAReportingSOS + fields = '__all__' + +class PIVerificationSerializer(ModelSerializer): + class Meta: + model = models.PIVerification + fields = '__all__' + +class DecideAcceptanceSerializer(ModelSerializer): + class Meta: + model = models.DecideAcceptance + fields = '__all__' + +class SchedulingUnitProcessSerializer(ModelSerializer): + class Meta: + model = models.SchedulingUnitProcess + fields = '__all__' \ No newline at end of file diff --git a/SAS/TMSS/src/tmss/workflowapp/templates/CMakeLists.txt b/SAS/TMSS/src/tmss/workflowapp/templates/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..3047f7e1561039003dec0c8630b75de4ce5f3037 --- /dev/null +++ b/SAS/TMSS/src/tmss/workflowapp/templates/CMakeLists.txt @@ -0,0 +1,10 @@ + +include(PythonInstall) + +set(_py_files + __init__.py + qa_reporting.html + ) + +python_install(${_py_files} + DESTINATION lofar/sas/tmss/tmss/workflowapp/templates) diff --git a/SAS/TMSS/src/tmss/workflowapp/templates/__init__.py b/SAS/TMSS/src/tmss/workflowapp/templates/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SAS/TMSS/src/tmss/workflowapp/templates/qa_reporting.html b/SAS/TMSS/src/tmss/workflowapp/templates/qa_reporting.html new file mode 100644 index 0000000000000000000000000000000000000000..822e7eb45e1677261b67fda229a2848d49963cfc --- /dev/null +++ b/SAS/TMSS/src/tmss/workflowapp/templates/qa_reporting.html @@ -0,0 +1 @@ +{% extends 'viewflow/flow/task.html' %} diff --git a/SAS/TMSS/src/tmss/workflowapp/viewsets/CMakeLists.txt b/SAS/TMSS/src/tmss/workflowapp/viewsets/CMakeLists.txt index 7adc12fcf7a85912784409d17f37177986c94298..eaf3c5ab4b9afa9063deda344de3644dcfbc388d 100644 --- a/SAS/TMSS/src/tmss/workflowapp/viewsets/CMakeLists.txt +++ b/SAS/TMSS/src/tmss/workflowapp/viewsets/CMakeLists.txt @@ -3,7 +3,7 @@ include(PythonInstall) set(_py_files __init__.py - schedulingunitdemoflow.py + schedulingunitflow.py ) python_install(${_py_files} diff --git a/SAS/TMSS/src/tmss/workflowapp/viewsets/__init__.py b/SAS/TMSS/src/tmss/workflowapp/viewsets/__init__.py index b77c70aeb959e9d4f63c395fd1079cfbbe3bc078..bfdfbc84e07beb363937412fd7fb6d5788c684d0 100644 --- a/SAS/TMSS/src/tmss/workflowapp/viewsets/__init__.py +++ b/SAS/TMSS/src/tmss/workflowapp/viewsets/__init__.py @@ -1 +1 @@ -from .schedulingunitdemoflow import * \ No newline at end of file +from .schedulingunitflow import * \ No newline at end of file diff --git a/SAS/TMSS/src/tmss/workflowapp/viewsets/schedulingunitdemoflow.py b/SAS/TMSS/src/tmss/workflowapp/viewsets/schedulingunitdemoflow.py deleted file mode 100644 index da3dc24e15ff6f3bd93da9037101a718f4ebed66..0000000000000000000000000000000000000000 --- a/SAS/TMSS/src/tmss/workflowapp/viewsets/schedulingunitdemoflow.py +++ /dev/null @@ -1,22 +0,0 @@ -from django.shortcuts import render -from rest_framework import viewsets -from rest_framework.response import Response -from rest_framework.decorators import action -from rest_framework.serializers import ModelSerializer -from lofar.sas.tmss.tmss.workflowapp import models - -# Create your views here. - -class SchedulingUnitDemoSerializer(ModelSerializer): - class Meta: - model = models.SchedulingUnitDemo - fields = '__all__' - -class SchedulingUnitFlowViewSet(viewsets.ModelViewSet): - queryset = models.SchedulingUnitDemo.objects.all() - serializer_class = SchedulingUnitDemoSerializer - - @action(methods=['get'], detail=True) - def trigger(self, request, pk=None): - SchedulingUnitDemoFlow - return Response("ok") \ No newline at end of file diff --git a/SAS/TMSS/src/tmss/workflowapp/viewsets/schedulingunitflow.py b/SAS/TMSS/src/tmss/workflowapp/viewsets/schedulingunitflow.py new file mode 100644 index 0000000000000000000000000000000000000000..1c70e87e110fd31d5f2533712165f973d0701733 --- /dev/null +++ b/SAS/TMSS/src/tmss/workflowapp/viewsets/schedulingunitflow.py @@ -0,0 +1,117 @@ +from django.shortcuts import render, redirect +from rest_framework import viewsets +from rest_framework.response import Response +from rest_framework.decorators import action +from lofar.sas.tmss.tmss.workflowapp import models + +from django.views import generic +from viewflow.flow.views import StartFlowMixin, FlowMixin +from viewflow.decorators import flow_start_view, flow_view +from viewflow.flow.views.utils import get_next_task_url +from django.forms import CharField, CheckboxInput +from django.forms.models import modelform_factory + + +from .. import forms, models, serializers + +class SchedulingUnitFlowViewSet(viewsets.ModelViewSet): + queryset = models.SchedulingUnit.objects.all() + serializer_class = serializers.SchedulingUnitSerializer + + @action(methods=['get'], detail=True) + def trigger(self, request, pk=None): + SchedulingUnitFlow + return Response("ok") + +#Viewsets and serializers to access intermediate steps of the QA Workflow +#through DRF +class QAReportingTOViewSet(viewsets.ModelViewSet): + queryset = models.QAReportingTO.objects.all() + serializer_class = serializers.QAReportingTOSerializer + +class QAReportingSOSViewSet(viewsets.ModelViewSet): + queryset = models.QAReportingSOS.objects.all() + serializer_class = serializers.QAReportingSOSSerializer + +class PIVerificationViewSet(viewsets.ModelViewSet): + queryset = models.PIVerification.objects.all() + serializer_class = serializers.PIVerificationSerializer + +class DecideAcceptanceViewSet(viewsets.ModelViewSet): + queryset = models.DecideAcceptance.objects.all() + serializer_class = serializers.DecideAcceptanceSerializer + +class SchedulingUnitProcessViewSet(viewsets.ModelViewSet): + queryset = models.SchedulingUnitProcess.objects.all() + serializer_class = serializers.SchedulingUnitProcessSerializer + +class QAReportingTOView(FlowMixin, generic.CreateView): + template_name = 'qa_reporting.html' + model = models.QAReportingTO + fields = [ + 'operator_report', 'operator_accept' + ] + + def form_valid(self, form): + report_data = form.save(commit=False) + report_data.save() + + self.activation.process.qa_reporting_to = report_data + self.activation.process.save() + + self.activation_done() + return redirect(self.get_success_url()) + + +class QAReportingSOSView(FlowMixin, generic.CreateView): + template_name = 'qa_reporting.html' + model = models.QAReportingSOS + fields = [ + 'sos_report', 'quality_within_policy','sos_accept_show_pi' + ] + + def form_valid(self, form): + report_data = form.save(commit=False) + report_data.save() + + self.activation.process.qa_reporting_sos = report_data + self.activation.process.save() + + self.activation_done() + return redirect(self.get_success_url()) + + +class PIVerificationView(FlowMixin, generic.CreateView): + template_name = 'qa_reporting.html' + model = models.PIVerification + fields = [ + 'pi_report', 'pi_accept' + ] + + def form_valid(self, form): + report_data = form.save(commit=False) + report_data.save() + + self.activation.process.pi_verification = report_data + self.activation.process.save() + + self.activation_done() + return redirect(self.get_success_url()) + + +class DecideAcceptanceView(FlowMixin, generic.CreateView): + template_name = 'qa_reporting.html' + model = models.DecideAcceptance + fields = [ + 'sos_accept_after_pi' + ] + + def form_valid(self, form): + report_data = form.save(commit=False) + report_data.save() + + self.activation.process.decide_acceptance = report_data + self.activation.process.save() + + self.activation_done() + return redirect(self.get_success_url()) \ No newline at end of file