Skip to content
Snippets Groups Projects
Commit aaafcd5c authored by Auke Klazema's avatar Auke Klazema
Browse files

Merge branch 'TMSS-215' into 'master'

Resolve TMSS-215

Closes TMSS-215

See merge request !210
parents 095c1ea8 b2053fe8
No related branches found
No related tags found
1 merge request!210Resolve TMSS-215
Showing
with 2279 additions and 16 deletions
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@apidevtools/json-schema-ref-parser": "^9.0.6",
"@fortawesome/fontawesome-free": "^5.13.1", "@fortawesome/fontawesome-free": "^5.13.1",
"@json-editor/json-editor": "^2.3.0", "@json-editor/json-editor": "^2.3.0",
"@testing-library/jest-dom": "^4.2.4", "@testing-library/jest-dom": "^4.2.4",
......
...@@ -94,7 +94,7 @@ p { ...@@ -94,7 +94,7 @@ p {
margin-bottom: 5px; margin-bottom: 5px;
} }
.p-grid span { .main-content .p-grid span {
margin-bottom: 10px; margin-bottom: 10px;
} }
...@@ -102,6 +102,10 @@ p { ...@@ -102,6 +102,10 @@ p {
margin-bottom: 0px; margin-bottom: 0px;
} }
.p-chips-token .p-chips-token-label {
margin-bottom: 0px !important;
}
.p-field { .p-field {
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
} }
......
...@@ -219,7 +219,115 @@ const ProjectServiceMock= { ...@@ -219,7 +219,115 @@ const ProjectServiceMock= {
"resource_type_id": "Support hours", "resource_type_id": "Support hours",
"value": 32400 "value": 32400
} }
] ],
projectList: [
{
"name": "OSR-01",
"url": "http://192.168.99.100:8008/api/project/OSR-01",
"can_trigger": false,
"created_at": "2020-08-25T14:29:04.881620",
"cycles": [
"http://192.168.99.100:8008/api/cycle/Cycle%2014"
],
"cycles_ids": [
"Cycle 14"
],
"description": "OSR-01",
"expert": false,
"filler": false,
"period_category": "http://192.168.99.100:8008/api/period_category/single_cycle",
"period_category_value": "single_cycle",
"priority_rank": 1,
"private_data": true,
"project_category": "http://192.168.99.100:8008/api/project_category/regular",
"project_category_value": "regular",
"quota": [
"http://192.168.99.100:8008/api/project_quota/1",
"http://192.168.99.100:8008/api/project_quota/2",
"http://192.168.99.100:8008/api/project_quota/3",
"http://192.168.99.100:8008/api/project_quota/4",
"http://192.168.99.100:8008/api/project_quota/5",
"http://192.168.99.100:8008/api/project_quota/6",
"http://192.168.99.100:8008/api/project_quota/7"
],
"quota_ids": [
1,
2,
3,
4,
5,
6,
7
],
"tags": [],
"trigger_priority": 1000,
"updated_at": "2020-08-25T14:29:04.881640"
},
{
"name": "OSR-02",
"url": "http://192.168.99.100:8008/api/project/OSR-02",
"can_trigger": false,
"created_at": "2020-08-28T07:52:07.411136",
"cycles": [],
"cycles_ids": [],
"description": "OSR-02",
"expert": false,
"filler": false,
"period_category": null,
"period_category_value": null,
"priority_rank": 1,
"private_data": true,
"project_category": null,
"project_category_value": null,
"quota": [
"http://192.168.99.100:8008/api/project_quota/8",
"http://192.168.99.100:8008/api/project_quota/9",
"http://192.168.99.100:8008/api/project_quota/10",
"http://192.168.99.100:8008/api/project_quota/11",
"http://192.168.99.100:8008/api/project_quota/12",
"http://192.168.99.100:8008/api/project_quota/13",
"http://192.168.99.100:8008/api/project_quota/14"
],
"quota_ids": [
8,
9,
10,
11,
12,
13,
14
],
"tags": [],
"trigger_priority": 1000,
"updated_at": "2020-08-28T07:52:07.411167"
},
{
"name": "TMSS-Commissioning",
"url": "http://192.168.99.100:8008/api/project/TMSS-Commissioning",
"can_trigger": false,
"created_at": "2020-08-25T13:28:34.760707",
"cycles": [
"http://192.168.99.100:8008/api/cycle/Cycle%2014"
],
"cycles_ids": [
"Cycle 14"
],
"description": "Project for all TMSS tests and commissioning",
"expert": true,
"filler": false,
"period_category": null,
"period_category_value": null,
"priority_rank": 1,
"private_data": true,
"project_category": null,
"project_category_value": null,
"quota": [],
"quota_ids": [],
"tags": [],
"trigger_priority": 1000,
"updated_at": "2020-08-25T13:28:34.760729"
}
]
} }
export default ProjectServiceMock; export default ProjectServiceMock;
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
...@@ -21,6 +21,18 @@ export default ({ title, subTitle, actions, ...props}) => { ...@@ -21,6 +21,18 @@ export default ({ title, subTitle, actions, ...props}) => {
} }
}; };
const onButtonClick = (e, action) => {
if (action.actOn && action.actOn === 'click') {
action.props.callback(e);
}
};
const onButtonMouseOver = (e, action) => {
if (action.actOn && action.actOn === 'mouseOver') {
action.props.callback(e);
}
}
return ( return (
<div className="page-header"> <div className="page-header">
<div className="title"> <div className="title">
...@@ -29,11 +41,22 @@ export default ({ title, subTitle, actions, ...props}) => { ...@@ -29,11 +41,22 @@ export default ({ title, subTitle, actions, ...props}) => {
</div> </div>
<div className="page-action-menu"> <div className="page-action-menu">
{(actions || []).map(action => { {(actions || []).map(action => {
return ( if (action.type === 'button') {
<Link to={{ ...action.props }} title={action.title || ''} onClick={() => onClickLink(action)}> return (
<i className={`fa ${action.icon}`}></i> <button className="p-link">
</Link> <i className={`fa ${action.icon}`}
)})} onMouseOver={(e) => onButtonMouseOver(e, action)}
onClick={(e) => onButtonClick(e, action)} />
</button>
);
} else {
return (
<Link to={{ ...action.props }} title={action.title || ''} onClick={() => onClickLink(action)}>
<i className={`fa ${action.icon}`}></i>
</Link>
);
}
})}
</div> </div>
</div> </div>
); );
......
...@@ -17,4 +17,8 @@ ...@@ -17,4 +17,8 @@
} }
.page-action-menu i { .page-action-menu i {
margin-left: 5px; margin-left: 5px;
}
.page-header .fa {
font-size: 25px !important;
} }
\ No newline at end of file
...@@ -93,7 +93,10 @@ export class CycleView extends Component { ...@@ -93,7 +93,10 @@ export class CycleView extends Component {
</div> </div>
} }
</div> */ } </div> */ }
<PageHeader location={this.props.location} title={'Cycle - View'} actions={[{icon:'fa-edit',title:'Click to Edit Cycle', props:{ pathname: `/cycle/edit/${this.state.cycle.name}`, state: {id: this.state.cycle?this.state.cycle.name:''}}},{name: 'fa-times',props:{ pathname: `/cycle`}}]}/> <PageHeader location={this.props.location} title={'Cycle - Details'}
actions={[ {icon:'fa-edit', title:'Click to Edit Cycle', props:{ pathname: `/cycle/edit/${this.state.cycle.name}`,
state: {id: this.state.cycle?this.state.cycle.name:''}}},
{icon: 'fa-window-close',props:{ pathname: `/cycle`}}]}/>
{ this.state.isLoading && <AppLoader /> } { this.state.isLoading && <AppLoader /> }
{ this.state.cycle && { this.state.cycle &&
<React.Fragment> <React.Fragment>
......
...@@ -4,6 +4,7 @@ import moment from 'moment'; ...@@ -4,6 +4,7 @@ import moment from 'moment';
import _ from 'lodash'; import _ from 'lodash';
import { Chips } from 'primereact/chips'; import { Chips } from 'primereact/chips';
import { TieredMenu } from 'primereact/tieredmenu';
import ResourceDisplayList from './ResourceDisplayList'; import ResourceDisplayList from './ResourceDisplayList';
...@@ -30,6 +31,11 @@ export class ProjectView extends Component { ...@@ -30,6 +31,11 @@ export class ProjectView extends Component {
} }
this.state.redirect = this.state.projectId?"":'/project' // If no project id is passed, redirect to Project list page this.state.redirect = this.state.projectId?"":'/project' // If no project id is passed, redirect to Project list page
this.resourceUnitMap = UnitConverter.resourceUnitMap; // Resource unit conversion factor and constraints this.resourceUnitMap = UnitConverter.resourceUnitMap; // Resource unit conversion factor and constraints
this.optionsMenu = React.createRef();
this.menuOptions = [ {label:'Add Scheduling Unit', icon: "fa fa-", command: () => {this.selectOptionMenu('Add SU')}} ];
this.showOptionMenu = this.showOptionMenu.bind(this);
this.selectOptionMenu = this.selectOptionMenu.bind(this);
} }
componentDidMount() { componentDidMount() {
...@@ -70,6 +76,22 @@ export class ProjectView extends Component { ...@@ -70,6 +76,22 @@ export class ProjectView extends Component {
} }
showOptionMenu(event) {
this.optionsMenu.toggle(event);
}
selectOptionMenu(menuName) {
switch(menuName) {
case 'Add SU': {
this.setState({redirect: `/project/${this.state.project.name}/schedulingunit/create`});
break;
}
default: {
break;
}
}
}
render() { render() {
if (this.state.redirect) { if (this.state.redirect) {
return <Redirect to={ {pathname: this.state.redirect} }></Redirect> return <Redirect to={ {pathname: this.state.redirect} }></Redirect>
...@@ -88,12 +110,27 @@ export class ProjectView extends Component { ...@@ -88,12 +110,27 @@ export class ProjectView extends Component {
</Link> </Link>
<Link to={{ pathname: `/project/edit/${this.state.project.name}`, state: {id: this.state.project?this.state.project.name:''}}} title="Edit Project" <Link to={{ pathname: `/project/edit/${this.state.project.name}`, state: {id: this.state.project?this.state.project.name:''}}} title="Edit Project"
style={{float: "right"}}> style={{float: "right"}}>
<i className="fa fa-edit" style={{marginTop: "10px"}}></i> <i className="fa fa-edit" style={{marginTop: "10px", marginLeft: "5px"}}></i>
</Link> </Link>
<TieredMenu model={this.menuOptions} popup ref={el => this.optionsMenu = el} />
<button className="p-link" style={{float: "right"}}>
<i className="fa fa-bars" label="Toggle Columns" style={{marginTop: "10px", marginLeft: "5px"}}
onMouseOver={(e) => this.optionsMenu.toggle(e)} />
</button>
</div> </div>
} }
</div> */} </div> */}
<PageHeader location={this.props.location} title={'Project - View'} actions={[{icon: 'fa-edit',title:'Click to Edit Project', props : { pathname: `/project/edit/${this.state.project.name}`, state: {id: this.state.project?this.state.project.name:''&& this.state.project}}},{icon:'fa-times',title: 'Click to Close Project View', props : { pathname: `/project`}}]}/> <TieredMenu model={this.menuOptions} popup ref={el => this.optionsMenu = el} />
<PageHeader location={this.props.location} title={'Project - View'}
actions={[ {icon:'fa-bars',title: '', type:'button',
actOn:'mouseOver', props : { callback: this.showOptionMenu}},
{icon: 'fa-edit',title:'Click to Edit Project', type:'link',
props : { pathname: `/project/edit/${this.state.project.name}`,
state: {id: this.state.project?this.state.project.name:''&& this.state.project}}},
{icon:'fa-window-close',title: 'Click to Close Project View', type:'link',
props : { pathname: `/project`}},
]}/>
{ this.state.isLoading && <AppLoader /> } { this.state.isLoading && <AppLoader /> }
{ this.state.project && { this.state.project &&
<React.Fragment> <React.Fragment>
......
...@@ -121,7 +121,8 @@ class ViewSchedulingUnit extends Component{ ...@@ -121,7 +121,8 @@ class ViewSchedulingUnit extends Component{
</Link> </Link>
</div> </div>
</div> */} </div> */}
<PageHeader location={this.props.location} title={'Scheduling Unit - Details'} actions={[{icon: 'fa-times',title:'Click to Close Scheduling Unit View', props : { pathname: '/schedulingunit'}}]}/> <PageHeader location={this.props.location} title={'Scheduling Unit - Details'}
actions={[{icon: 'fa-window-close',title:'Click to Close Scheduling Unit View', props : { pathname: '/schedulingunit'}}]}/>
{ this.state.isLoading ? <AppLoader/> :this.state.scheduleunit && { this.state.isLoading ? <AppLoader/> :this.state.scheduleunit &&
<> <>
<div className="main-content"> <div className="main-content">
......
This diff is collapsed.
import React from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import { act } from "react-dom/test-utils";
import { render, cleanup, fireEvent } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import {SchedulingUnitCreate} from './create';
import ScheduleService from '../../services/schedule.service';
import ProjectService from '../../services/project.service';
import TaskService from '../../services/task.service';
import SUServiceMock from '../../__mocks__/scheduleunit.service.data';
import ProjectServiceMock from '../../__mocks__/project.service.data';
import TaskServiceMock from '../../__mocks__/task.service.data';
let projectListSpy, scheduleSetListSpy, observStrategiesSpy, taskTemplatesSpy, saveSUFromStrategySpy, updateSUSpy, createSUTasksSpy;
beforeEach(() => {
setMockSpy();
});
afterEach(() => {
// cleanup on exiting
clearMockSpy();
cleanup();
});
const setMockSpy = () => {
projectListSpy = jest.spyOn(ProjectService, 'getProjectList');
projectListSpy.mockImplementation(() => { return Promise.resolve(ProjectServiceMock.projectList)});
scheduleSetListSpy = jest.spyOn(ScheduleService, 'getSchedulingSets');
scheduleSetListSpy.mockImplementation(() => { return Promise.resolve(SUServiceMock.scheduleSetList)});
observStrategiesSpy = jest.spyOn(ScheduleService, 'getObservationStrategies');
observStrategiesSpy.mockImplementation(() => { return Promise.resolve(SUServiceMock.observStrategies)});
taskTemplatesSpy = jest.spyOn(TaskService, 'getTaskTemplates');
taskTemplatesSpy.mockImplementation(() => { return Promise.resolve(TaskServiceMock.taskTemplates)});
saveSUFromStrategySpy = jest.spyOn(ScheduleService, 'saveSUDraftFromObservStrategy');
saveSUFromStrategySpy.mockImplementation((observStrategy, schedulingUnit) => {
return Promise.resolve(SUServiceMock.schedulingUnitFromObservStrategy);
});
updateSUSpy = jest.spyOn(ScheduleService, 'updateSchedulingUnitDraft');
updateSUSpy.mockImplementation((schedulingUnit) => {
return Promise.resolve(SUServiceMock.schedulingUnitFromObservStrategy);
});
createSUTasksSpy = jest.spyOn(ScheduleService, 'createSUTaskDrafts');
createSUTasksSpy.mockImplementation((schedulingUnit) => {
return Promise.resolve(SUServiceMock.schedulingUnitFromObservStrategy);
});
}
const clearMockSpy = () => {
projectListSpy.mockRestore();
scheduleSetListSpy.mockRestore();
observStrategiesSpy.mockRestore();
taskTemplatesSpy.mockRestore();
saveSUFromStrategySpy.mockRestore();
updateSUSpy.mockRestore();
createSUTasksSpy.mockRestore();
}
it("renders create page with all fields and default values", async() => {
console.log("renders create page with all fields and default values ------------------------");
let content;
await act(async () => {
content = render(<Router><SchedulingUnitCreate /></Router>);
});
expect(content.queryByText('Scheduling Unit - Add')).not.toBe(null); // Page loaded successfully
expect(projectListSpy).toHaveBeenCalled(); // Mock Spy called successfully
expect(observStrategiesSpy).toHaveBeenCalled(); // Mock Spy called successfully
expect(scheduleSetListSpy).toHaveBeenCalled(); // Mock Spy called successfully
expect(taskTemplatesSpy).toHaveBeenCalled(); // Mock Spy called successfully
expect(content.queryByText('TMSS-Commissioning')).toBeInTheDocument(); // Project Dropdown loaded successfully
expect(content.queryByText('UC1 observation strategy template')).toBeInTheDocument(); // Observation Strategy Dropdown loaded successfully
expect(content.queryByText('Task Parameters')).not.toBeInTheDocument(); // JSON Editor not rendered
expect(content.queryByTestId('save-btn')).toHaveAttribute("disabled");
});
it("creates new Scheduling Unit with default values", async() => {
console.log("creates new Scheduling Unit with default values ------------------------");
let content;
await act(async () => {
content = render(<Router><SchedulingUnitCreate /></Router>);
});
const nameInput = content.queryByTestId('name');
const descInput = content.queryByTestId('description');
const projInput = content.getAllByRole("listbox")[0].children[2] ;
const observStrategyInput = content.getAllByRole("listbox")[2].children[0] ;
// Set values for all mandatory input and test if save button is enabled
fireEvent.change(nameInput, { target: { value: 'UC1 test scheduling unit 1.1' } });
expect(nameInput.value).toBe("UC1 test scheduling unit 1.1");
fireEvent.change(descInput, { target: { value: 'UC1 test scheduling unit 1.1' } });
expect(descInput.value).toBe("UC1 test scheduling unit 1.1");
// After selecting values for all dropdowns
await act(async () => {
fireEvent.click(projInput);
});
const schedulingSetInput = content.getAllByRole("listbox")[1].children[0] ;
expect(content.queryAllByText('Select Project').length).toBe(1);
expect(content.queryAllByText('TMSS-Commissioning').length).toBe(3);
await act(async () => {
fireEvent.click(schedulingSetInput);
});
expect(content.queryAllByText('Select Scheduling Set').length).toBe(1);
expect(content.queryAllByText('Test Scheduling Set UC1 example 0').length).toBe(3);
await act( async() => {
fireEvent.click(observStrategyInput);
});
expect(content.queryAllByText('Select Strategy').length).toBe(1);
expect(content.queryAllByText('UC1 observation strategy template').length).toBe(3);
expect(content.queryByText('Task Parameters')).toBeInTheDocument();
expect(content.queryByText('Target Pointing 0')).toBeInTheDocument();
expect(content.queryByText('Not a valid input. Mimimum: 00:00:00, Maximum:23:59:59.')).not.toBeInTheDocument();
expect(content.queryByText('Not a valid input. Mimimum: 00:00:00, Maximum:90:00:00.')).not.toBeInTheDocument();
/* This is set again to call the validateEditor function in the component.
If this is removed, the editor validation will not occur in the test but works in browser.*/
await act( async() => {
fireEvent.change(nameInput, { target: { value: 'UC1 test scheduling unit 1.1' } });
});
expect(content.queryByTestId('save-btn').hasAttribute("disabled")).toBeFalsy();
await act(async () => {
fireEvent.click(content.queryByTestId('save-btn'));
});
expect(saveSUFromStrategySpy).toHaveBeenCalled();
});
\ No newline at end of file
...@@ -15,7 +15,9 @@ export class Scheduling extends Component { ...@@ -15,7 +15,9 @@ export class Scheduling extends Component {
render() { render() {
return ( return (
<> <>
<PageHeader location={this.props.location} title={'Scheduling Unit - List'}/> <PageHeader location={this.props.location} title={'Scheduling Unit - List'}
actions={[{icon: 'fa fa-plus-square', title: 'Add New Scheduling Unit',
props: {pathname: '/schedulingunit/create'}}]} />
{this.state.scheduleunit && {this.state.scheduleunit &&
<SchedulingUnitList /> } <SchedulingUnitList /> }
</> </>
......
...@@ -123,7 +123,7 @@ export class TaskView extends Component { ...@@ -123,7 +123,7 @@ export class TaskView extends Component {
state: {taskId: this.state.task?this.state.task.id:''} state: {taskId: this.state.task?this.state.task.id:''}
} }
}, },
{ icon: 'fa-times', { icon: 'fa-window-close',
title:'Click to Close Task', title:'Click to Close Task',
props : { pathname:'/task' }}]; props : { pathname:'/task' }}];
} else { } else {
......
...@@ -10,7 +10,8 @@ import {ProjectList, ProjectCreate, ProjectView, ProjectEdit} from './Project'; ...@@ -10,7 +10,8 @@ import {ProjectList, ProjectCreate, ProjectView, ProjectEdit} from './Project';
import {Dashboard} from './Dashboard'; import {Dashboard} from './Dashboard';
import {Scheduling} from './Scheduling'; import {Scheduling} from './Scheduling';
import {TaskEdit, TaskView} from './Task'; import {TaskEdit, TaskView} from './Task';
import ViewSchedulingUnit from './Scheduling/ViewSchedulingUnit' import ViewSchedulingUnit from './Scheduling/ViewSchedulingUnit';
import SchedulingUnitCreate from './Scheduling/create';
import { CycleList, CycleCreate, CycleView, CycleEdit } from './Cycle'; import { CycleList, CycleCreate, CycleView, CycleEdit } from './Cycle';
export const routes = [ export const routes = [
...@@ -28,6 +29,10 @@ export const routes = [ ...@@ -28,6 +29,10 @@ export const routes = [
component: Scheduling, component: Scheduling,
name: 'Scheduling Unit', name: 'Scheduling Unit',
title: 'Scheduling Unit - List' title: 'Scheduling Unit - List'
},{
path: "/schedulingunit/create",
component: SchedulingUnitCreate,
name: 'Scheduling Unit Add'
},{ },{
path: "/task", path: "/task",
component: TaskView, component: TaskView,
...@@ -83,8 +88,12 @@ export const routes = [ ...@@ -83,8 +88,12 @@ export const routes = [
component: ProjectEdit, component: ProjectEdit,
name: 'Project Edit', name: 'Project Edit',
title: 'Project Edit' title: 'Project Edit'
}, },{
{ path: "/project/:project/schedulingunit/create",
component: SchedulingUnitCreate,
name: 'Scheduling Unit Add',
title: 'Scheduling Unit - Add'
},{
path: "/cycle/edit/:id", path: "/cycle/edit/:id",
component: CycleEdit, component: CycleEdit,
name: 'Cycle Edit', name: 'Cycle Edit',
......
...@@ -166,6 +166,68 @@ const ScheduleService = { ...@@ -166,6 +166,68 @@ const ScheduleService = {
}); });
return res; return res;
}, },
getSchedulingSets: async function() {
try {
const response = await axios.get('/api/scheduling_set/');
return response.data.results;
} catch(error) {
console.error(error);
return [];
};
},
getObservationStrategies: async function() {
try {
const response = await axios.get('/api/scheduling_unit_observing_strategy_template/');
return response.data.results;
} catch(error) {
console.error(error);
return [];
};
},
saveSUDraftFromObservStrategy: async function(observStrategy, schedulingUnit) {
try {
// Create the scheduling unit draft with observation strategy and scheduling set
const url = `/api/scheduling_unit_observing_strategy_template/${observStrategy.id}/create_scheduling_unit/?scheduling_set_id=${schedulingUnit.scheduling_set_id}&name=${schedulingUnit.name}&description=${schedulingUnit.description}`
const suObsResponse = await axios.get(url);
schedulingUnit = suObsResponse.data;
if (schedulingUnit && schedulingUnit.id) {
// Update the newly created SU draft requirement_doc with captured parameter values
schedulingUnit.requirements_doc = observStrategy.template;
delete schedulingUnit['duration'];
schedulingUnit = await this.updateSchedulingUnitDraft(schedulingUnit);
if (!schedulingUnit || !schedulingUnit.id) {
return null;
}
// Create task drafts with updated requirement_doc
schedulingUnit = await this.createSUTaskDrafts(schedulingUnit);
if (schedulingUnit && schedulingUnit.task_drafts.length > 0) {
return schedulingUnit;
}
}
return null;
} catch(error) {
console.error(error);
return null;
};
},
updateSchedulingUnitDraft: async function(schedulingUnit) {
try {
const suUpdateResponse = await axios.put(`/api/scheduling_unit_draft/${schedulingUnit.id}/`, schedulingUnit);
return suUpdateResponse.data;
} catch(error) {
console.error(error);
return null
}
},
createSUTaskDrafts: async (schedulingUnit) => {
try {
const suCreateTaskResponse = await axios.get(`/api/scheduling_unit_draft/${schedulingUnit.id}/create_task_drafts/`);
return suCreateTaskResponse.data;
} catch(error) {
console.error(error);
return null;
}
}
} }
export default ScheduleService; export default ScheduleService;
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment