From dc0e517fd5918b8b1ef0186ab617d4f847cdcc0f Mon Sep 17 00:00:00 2001 From: Reinder Kraaij <kraaij@astron.nl> Date: Mon, 20 Nov 2023 21:41:16 +0100 Subject: [PATCH] Let there be a Project change dialog --- .../tmss_webapp/src/routes/Project/create.js | 4 +- .../tmss_webapp/src/routes/Project/list.js | 89 +++++++------------ .../src/routes/Project/projectStatusDialog.js | 61 +++++++++++++ .../src/services/project.service.js | 7 +- 4 files changed, 102 insertions(+), 59 deletions(-) create mode 100644 SAS/TMSS/frontend/tmss_webapp/src/routes/Project/projectStatusDialog.js diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Project/create.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Project/create.js index ba9a85fcf8d..21d84310dba 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Project/create.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Project/create.js @@ -468,8 +468,8 @@ export class ProjectCreate extends Component { return ( <React.Fragment> <Toast ref={(el) => this.growl = el} /> - <PageHeader location={this.props.location} title={'Project - Add'} actions={[{icon:'fa-window-close', title:'Click to Close Project', - type: 'button', actOn: 'click', props:{ callback: this.checkIsDirty }}]}/> + <PageHeader className="defaultpageHeader" location={this.props.location} title={'Project - Add'} actions={[{icon:'pi pi-times', title:'Click to Close Project', + type: 'buttonv2', actOn: 'click', props:{ callback: this.checkIsDirty }}]}/> { this.state.isLoading ? <AppLoader /> : <> <div style={{marginBottom: '2em'}}> diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Project/list.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Project/list.js index cbf021d9f8e..7ad7b80b0bd 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Project/list.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Project/list.js @@ -7,15 +7,13 @@ import CycleService from '../../services/cycle.service'; import UtilService from '../../services/util.service'; import AuthUtil from '../../utils/auth.util'; import _ from 'lodash'; -import { Dialog } from 'primereact/dialog'; -import { RadioButton } from 'primereact/radiobutton'; -import { Button } from 'primereact/button'; + import { CustomDialog } from '../../layout/components/CustomDialog'; import { Column } from 'primereact/column'; import { DataTable } from 'primereact/datatable'; import { appGrowl } from '../../layout/components/AppGrowl'; import TopProgressBar from '../../layout/components/TopProgressBar'; - +import ProjectStatusDialog from './projectStatusDialog' export class ProjectList extends Component { lsTableName = 'project_list'; lsKeySortColumn = "projectSortData"; @@ -263,7 +261,7 @@ export class ProjectList extends Component { let changedData = []; for (const row of this.selectedRows) { let changedRow = {} - changedRow.project_state_value = this.state.changedStatus.value; + changedRow.project_state_value = this.state.changedStatus; changedRow.name = row.name; changedData.push(changedRow); } @@ -360,7 +358,7 @@ export class ProjectList extends Component { let statusChangeResponse = [] for (const row of this.selectedRows) { row.project_state = this.state.changedStatus.url - row.project_state_value = this.state.changedStatus.value; + row.project_state_value = this.state.changedStatus; let response = await ProjectService.updateProject(row.name, row) if(response.isUpdated) { statusChangeResponse.push({ @@ -414,36 +412,34 @@ export class ProjectList extends Component { + prepareSaveProjectStatus = (projectStatus) => { + this.setState({ changedStatus: projectStatus },() =>this.confirmStatusChange()); + } + + gotoAdd = () =>{ + + this.props. history.push("/project/create") ; + + } render() { - const footer = ( - <div > - <Button label="Save" className="p-button-primary p-mr-2" icon="pi pi-check" disabled={!this.state.changedStatus} onClick={this.confirmStatusChange } data-testid="save-btn" /> - <Button label="Cancel" className="act-btn-cancel mr-0" icon="pi pi-times" onClick={() => this.setState({showStatusUpdateDialog: false})} /> - </div> - ); + return ( <> - {/*<div className="p-grid"> - <div className="p-col-10 p-lg-10 p-md-10"> - <h2>Project - List </h2> - </div> - <div className="p-col-2 p-lg-2 p-md-2"> - <Link to={{ pathname: '/project/create'}} title="Add New Project" style={{float: "right"}}> - <i className="fa fa-plus-square" style={{marginTop: "10px"}}></i> - </Link> - </div> - </div> */} { (this.props.cycle) ? <> </> : - <PageHeader location={this.props.location} title={'Project - List'} - actions={[{icon: 'fa fa-tag',title: this.state.userrole && this.state.userrole.userRolePermission.project && this.state.userrole.userRolePermission.project.edit?'Update Project(s) Status':"Don't have permission to Update Status", + <PageHeader location={this.props.location} title={'Project - List'} className="defaultpageHeader" + actions={[{icon: 'pi pi-briefcase',title: this.state.userrole && this.state.userrole.userRolePermission.project && this.state.userrole.userRolePermission.project.edit?'Update Project(s) Status':"Don't have permission to Update Status", disabled: this.state.userrole && this.state.userrole.userRolePermission.project?!this.state.userrole.userRolePermission.project.edit:true, - type: 'button', actOn: 'click', props: { callback: this.showStatusChangeDialog }}, - { icon: 'fa-plus-square', title: this.state.userrole && this.state.userrole.userRolePermission.project && this.state.userrole.userRolePermission.project.create?'Click to Add Project':"Don't have permission to add new Project", - disabled: this.state.userrole && this.state.userrole.userRolePermission.project?!this.state.userrole.userRolePermission.project.create:true, props: { pathname: '/project/create' }}]} - /> + type: 'buttonv2', actOn: 'click', props: { callback: this.showStatusChangeDialog }}, + { + icon: 'pi-plus', + type: 'buttonv2', + title: this.state.userrole && this.state.userrole.userRolePermission.project && this.state.userrole.userRolePermission.project.create?'Click to Add Project':"Don't have permission to add new Project", + disabled: this.state.userrole && this.state.userrole.userRolePermission.project?!this.state.userrole.userRolePermission.project.create:true, + actOn: 'click', props:{ callback:this.gotoAdd }}]}/> + } {this.state.isLoading ? <AppLoader /> : (this.state.isprocessed && this.state.projectlist.length > 0) ? <div> @@ -473,38 +469,19 @@ export class ProjectList extends Component { } {this.state.showStatusUpdateDialog && <div> - <Dialog header={`Update Project(s) Status`} - footer={footer} maximizable= {false} - visible={this.state.showStatusUpdateDialog} maximized={false} position="center" style={{ width: '20vw' }} - onHide={() => { this.setState({ showStatusUpdateDialog: false }) }} - className="content_dlg"> - <div style={{ width: '100%' }}> - <div className="p-fluid"> - <div className="p-grid p-field" style={{ paddingLeft: '15px' }}>Select the status and click 'Save' to update.</div> - {this.statusOptions.map((option) => { - return ( - <div className="p-col-12" style={{width: "100%"}} key={option.value} > - <RadioButton - inputId={option.value} - name={option.value} - value={option.value} - onChange={() => this.setState({ changedStatus: option })} - checked={this.state.changedStatus && this.state.changedStatus.value === option.value} - /> - <label htmlFor={option.value} className='p-radiobutton-label' style={{textTransform: 'capitalize'}}> - {option.value} - </label> - </div> - ) - })} - </div> - </div> - </Dialog> + <ProjectStatusDialog + statusOptions= {this.statusOptions} + visible={this.state.showStatusUpdateDialog} + onHide={ () => { this.setState({ showStatusUpdateDialog: false }) }} + onCancel={ () => { this.setState({ showStatusUpdateDialog: false }) }} + onSave={ (projectStatus) => {this.prepareSaveProjectStatus(projectStatus)}} + /> + <CustomDialog type="confirmation" visible={this.state.dialog && this.state.dialog.dialogVisible} header={this.state.dialog && this.state.dialog.header} message={this.state.dialog && this.state.dialog.detail} actions={this.state.dialog && this.state.dialog.actions} content={this.state.dialog && this.state.dialog.content} width={this.state.dialog && this.state.dialog.width} showIcon={this.state.dialog && this.state.dialog.showIcon} onClose={this.closeDialog} onCancel={this.closeDialog}/> - </div> + </div> } </> ) diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Project/projectStatusDialog.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Project/projectStatusDialog.js new file mode 100644 index 00000000000..463d145060e --- /dev/null +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Project/projectStatusDialog.js @@ -0,0 +1,61 @@ + +import { useState } from "react"; +import { RadioButton } from "primereact/radiobutton"; +import { Dialog } from 'primereact/dialog'; +import { Button } from 'primereact/button'; + +export default function ProjectStatusDialog(props) { + const { + visible, + onSave, + onHide, + onCancel, + statusOptions + } = props + + const [projectStatus, setProjectStatus] = useState(''); + + + const Save = () => { + if (!onSave) return; + onSave(projectStatus); + + } + + const footer = ( + <div > + <Button label="Save" className="p-button-primary p-mr-2" icon="pi pi-check" disabled={projectStatus==''} onClick={Save} data-testid="save-btn" /> + <Button label="Cancel" className="act-btn-cancel mr-0" icon="pi pi-times" onClick={onCancel} /> + </div> + ); + return ( + <Dialog header={`Update Project(s) Status`} + footer={footer} maximizable= {false} + visible={visible} maximized={false} position="center" style={{ width: '20vw' }} + onHide={onHide} + className="content_dlg"> + <div style={{ width: '100%' }}> + <div className="p-fluid"> + <div className="p-grid p-field" style={{ paddingLeft: '15px' }}>Select the status and click 'Save' to update.</div> + {statusOptions?.map((option) => { + return ( + <div className="p-col-12 p-2 " style={{width: "100%"}} key={option.value} > + <RadioButton + inputId={option.value} + name={option.value} + value={option.value} + onChange={(e) => setProjectStatus(e.value)} + checked= {projectStatus === option.value} + /> + <label htmlFor={option.value} className='p-radiobutton-label' style={{textTransform: 'capitalize'}}> + {option.value} + </label> + </div> + ) + })} + </div> + </div> + </Dialog> + ); +} + \ No newline at end of file diff --git a/SAS/TMSS/frontend/tmss_webapp/src/services/project.service.js b/SAS/TMSS/frontend/tmss_webapp/src/services/project.service.js index d4ce5c47a48..9b8f9e37fad 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/services/project.service.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/services/project.service.js @@ -338,7 +338,12 @@ const ProjectService = { const response = await axios.get(`/api/project/${projectName}/friend`); return response.data; } catch (error) { - console.error('[project.services.getFriendsforProject]',error); + if (error?.response?.data?.indexOf("Keycloak admin API token could not be obtained")>0) { + console.info('The Friend list does not work. This is expected behavoir on Dev.',error); + } else + { + console.error('[project.services.getFriendsforProject]',error); + } return []; } }, -- GitLab