Skip to content

Commit 7f0a05c

Browse files
committed
UPdate remainder of screens with basic permissions checking
1 parent 171b21e commit 7f0a05c

File tree

5 files changed

+94
-71
lines changed

5 files changed

+94
-71
lines changed

resources/scripts/components/server/databases/DatabaseRow.tsx

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import React, { useState } from 'react';
2-
import { ServerDatabase } from '@/api/server/getServerDatabases';
32
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
43
import { faDatabase } from '@fortawesome/free-solid-svg-icons/faDatabase';
54
import { faTrashAlt } from '@fortawesome/free-solid-svg-icons/faTrashAlt';
@@ -16,6 +15,7 @@ import { ServerContext } from '@/state/server';
1615
import deleteServerDatabase from '@/api/server/deleteServerDatabase';
1716
import { httpErrorToHuman } from '@/api/http';
1817
import RotatePasswordButton from '@/components/server/databases/RotatePasswordButton';
18+
import Can from '@/components/elements/Can';
1919

2020
interface Props {
2121
databaseId: string | number;
@@ -24,10 +24,10 @@ interface Props {
2424
}
2525

2626
export default ({ databaseId, className, onDelete }: Props) => {
27-
const [visible, setVisible] = useState(false);
27+
const [ visible, setVisible ] = useState(false);
2828
const database = ServerContext.useStoreState(state => state.databases.items.find(item => item.id === databaseId));
2929
const appendDatabase = ServerContext.useStoreActions(actions => actions.databases.appendDatabase);
30-
const [connectionVisible, setConnectionVisible] = useState(false);
30+
const [ connectionVisible, setConnectionVisible ] = useState(false);
3131
const { addFlash, clearFlashes } = useStoreActions((actions: Actions<ApplicationStore>) => actions.flashes);
3232
const server = ServerContext.useStoreState(state => state.server.data!);
3333

@@ -38,7 +38,7 @@ export default ({ databaseId, className, onDelete }: Props) => {
3838
const schema = object().shape({
3939
confirm: string()
4040
.required('The database name must be provided.')
41-
.oneOf([database.name.split('_', 2)[1], database.name], 'The database name must be provided.'),
41+
.oneOf([ database.name.split('_', 2)[1], database.name ], 'The database name must be provided.'),
4242
});
4343

4444
const submit = (values: { confirm: string }, { setSubmitting }: FormikHelpers<{ confirm: string }>) => {
@@ -73,7 +73,10 @@ export default ({ databaseId, className, onDelete }: Props) => {
7373
visible={visible}
7474
dismissable={!isSubmitting}
7575
showSpinnerOverlay={isSubmitting}
76-
onDismissed={() => { setVisible(false); resetForm(); }}
76+
onDismissed={() => {
77+
setVisible(false);
78+
resetForm();
79+
}}
7780
>
7881
<FlashMessageRender byKey={'delete-database-modal'} className={'mb-6'}/>
7982
<h3 className={'mb-6'}>Confirm database deletion</h3>
@@ -113,10 +116,12 @@ export default ({ databaseId, className, onDelete }: Props) => {
113116
<Modal visible={connectionVisible} onDismissed={() => setConnectionVisible(false)}>
114117
<FlashMessageRender byKey={'database-connection-modal'} className={'mb-6'}/>
115118
<h3 className={'mb-6'}>Database connection details</h3>
116-
<div>
117-
<label className={'input-dark-label'}>Password</label>
118-
<input type={'text'} className={'input-dark'} readOnly={true} value={database.password}/>
119-
</div>
119+
<Can action={'database.view_password'}>
120+
<div>
121+
<label className={'input-dark-label'}>Password</label>
122+
<input type={'text'} className={'input-dark'} readOnly={true} value={database.password}/>
123+
</div>
124+
</Can>
120125
<div className={'mt-6'}>
121126
<label className={'input-dark-label'}>JBDC Connection String</label>
122127
<input
@@ -127,7 +132,9 @@ export default ({ databaseId, className, onDelete }: Props) => {
127132
/>
128133
</div>
129134
<div className={'mt-6 text-right'}>
130-
<RotatePasswordButton databaseId={database.id} onUpdate={appendDatabase}/>
135+
<Can action={'database.update'}>
136+
<RotatePasswordButton databaseId={database.id} onUpdate={appendDatabase}/>
137+
</Can>
131138
<button className={'btn btn-sm btn-secondary'} onClick={() => setConnectionVisible(false)}>
132139
Close
133140
</button>
@@ -156,9 +163,11 @@ export default ({ databaseId, className, onDelete }: Props) => {
156163
<button className={'btn btn-sm btn-secondary mr-2'} onClick={() => setConnectionVisible(true)}>
157164
<FontAwesomeIcon icon={faEye} fixedWidth={true}/>
158165
</button>
159-
<button className={'btn btn-sm btn-secondary btn-red'} onClick={() => setVisible(true)}>
160-
<FontAwesomeIcon icon={faTrashAlt} fixedWidth={true}/>
161-
</button>
166+
<Can action={'database.delete'}>
167+
<button className={'btn btn-sm btn-secondary btn-red'} onClick={() => setVisible(true)}>
168+
<FontAwesomeIcon icon={faTrashAlt} fixedWidth={true}/>
169+
</button>
170+
</Can>
162171
</div>
163172
</div>
164173
</React.Fragment>

resources/scripts/components/server/databases/DatabasesContainer.tsx

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { useEffect, useState } from 'react';
2-
import getServerDatabases, { ServerDatabase } from '@/api/server/getServerDatabases';
2+
import getServerDatabases from '@/api/server/getServerDatabases';
33
import { ServerContext } from '@/state/server';
44
import { Actions, useStoreActions } from 'easy-peasy';
55
import { ApplicationStore } from '@/state';
@@ -9,6 +9,7 @@ import DatabaseRow from '@/components/server/databases/DatabaseRow';
99
import Spinner from '@/components/elements/Spinner';
1010
import { CSSTransition } from 'react-transition-group';
1111
import CreateDatabaseButton from '@/components/server/databases/CreateDatabaseButton';
12+
import Can from '@/components/elements/Can';
1213

1314
export default () => {
1415
const [ loading, setLoading ] = useState(true);
@@ -41,7 +42,7 @@ export default () => {
4142
<Spinner size={'large'} centered={true}/>
4243
:
4344
<CSSTransition classNames={'fade'} timeout={250}>
44-
<React.Fragment>
45+
<>
4546
{databases.length > 0 ?
4647
databases.map((database, index) => (
4748
<DatabaseRow
@@ -54,18 +55,20 @@ export default () => {
5455
:
5556
<p className={'text-center text-sm text-neutral-400'}>
5657
{server.featureLimits.databases > 0 ?
57-
`It looks like you have no databases. Click the button below to create one now.`
58+
`It looks like you have no databases.`
5859
:
5960
`Databases cannot be created for this server.`
6061
}
6162
</p>
6263
}
63-
{server.featureLimits.databases > 0 &&
64-
<div className={'mt-6 flex justify-end'}>
65-
<CreateDatabaseButton onCreated={appendDatabase}/>
66-
</div>
67-
}
68-
</React.Fragment>
64+
<Can action={'database.create'}>
65+
{server.featureLimits.databases > 0 &&
66+
<div className={'mt-6 flex justify-end'}>
67+
<CreateDatabaseButton onCreated={appendDatabase}/>
68+
</div>
69+
}
70+
</Can>
71+
</>
6972
</CSSTransition>
7073
}
7174
</div>

resources/scripts/components/server/schedules/ScheduleContainer.tsx

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { httpErrorToHuman } from '@/api/http';
99
import { Actions, useStoreActions } from 'easy-peasy';
1010
import { ApplicationStore } from '@/state';
1111
import EditScheduleModal from '@/components/server/schedules/EditScheduleModal';
12+
import Can from '@/components/elements/Can';
1213

1314
export default ({ match, history }: RouteComponentProps) => {
1415
const { uuid } = ServerContext.useStoreState(state => state.server.data!);
@@ -35,9 +36,8 @@ export default ({ match, history }: RouteComponentProps) => {
3536
<>
3637
{
3738
schedules.length === 0 ?
38-
<p className={'text-sm text-neutral-400'}>
39-
There are no schedules configured for this server. Click the button below to get
40-
started.
39+
<p className={'text-sm text-center text-neutral-400'}>
40+
There are no schedules configured for this server.
4141
</p>
4242
:
4343
schedules.map(schedule => (
@@ -54,21 +54,23 @@ export default ({ match, history }: RouteComponentProps) => {
5454
</a>
5555
))
5656
}
57-
<div className={'mt-8 flex justify-end'}>
58-
{visible && <EditScheduleModal
59-
appear={true}
60-
visible={true}
61-
onScheduleUpdated={schedule => setSchedules(s => [...(s || []), schedule])}
62-
onDismissed={() => setVisible(false)}
63-
/>}
64-
<button
65-
type={'button'}
66-
className={'btn btn-lg btn-primary'}
67-
onClick={() => setVisible(true)}
68-
>
69-
Create schedule
70-
</button>
71-
</div>
57+
<Can action={'schedule.create'}>
58+
<div className={'mt-8 flex justify-end'}>
59+
{visible && <EditScheduleModal
60+
appear={true}
61+
visible={true}
62+
onScheduleUpdated={schedule => setSchedules(s => [ ...(s || []), schedule ])}
63+
onDismissed={() => setVisible(false)}
64+
/>}
65+
<button
66+
type={'button'}
67+
className={'btn btn-sm btn-primary'}
68+
onClick={() => setVisible(true)}
69+
>
70+
Create schedule
71+
</button>
72+
</div>
73+
</Can>
7274
</>
7375
}
7476
</div>

resources/scripts/components/server/schedules/ScheduleEditContainer.tsx

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import ScheduleTaskRow from '@/components/server/schedules/ScheduleTaskRow';
1313
import EditScheduleModal from '@/components/server/schedules/EditScheduleModal';
1414
import NewTaskButton from '@/components/server/schedules/NewTaskButton';
1515
import DeleteScheduleButton from '@/components/server/schedules/DeleteScheduleButton';
16+
import Can from '@/components/elements/Can';
1617

1718
interface Params {
1819
id: string;
@@ -93,24 +94,27 @@ export default ({ match, history, location: { state } }: RouteComponentProps<Par
9394
</>
9495
:
9596
<p className={'text-sm text-neutral-400'}>
96-
There are no tasks configured for this schedule. Consider adding a new one using the
97-
button below.
97+
There are no tasks configured for this schedule.
9898
</p>
9999
}
100100
<div className={'mt-8 flex justify-end'}>
101-
<DeleteScheduleButton
102-
scheduleId={schedule.id}
103-
onDeleted={() => history.push(`/server/${id}/schedules`)}
104-
/>
105-
<button className={'btn btn-primary btn-sm mr-4'} onClick={() => setShowEditModal(true)}>
106-
Edit
107-
</button>
108-
<NewTaskButton
109-
scheduleId={schedule.id}
110-
onTaskAdded={task => setSchedule(s => ({
111-
...s!, tasks: [ ...s!.tasks, task ],
112-
}))}
113-
/>
101+
<Can action={'schedule.delete'}>
102+
<DeleteScheduleButton
103+
scheduleId={schedule.id}
104+
onDeleted={() => history.push(`/server/${id}/schedules`)}
105+
/>
106+
</Can>
107+
<Can action={'schedule.update'}>
108+
<button className={'btn btn-primary btn-sm mr-4'} onClick={() => setShowEditModal(true)}>
109+
Edit
110+
</button>
111+
<NewTaskButton
112+
scheduleId={schedule.id}
113+
onTaskAdded={task => setSchedule(s => ({
114+
...s!, tasks: [ ...s!.tasks, task ],
115+
}))}
116+
/>
117+
</Can>
114118
</div>
115119
</>
116120
}

resources/scripts/components/server/schedules/ScheduleTaskRow.tsx

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { httpErrorToHuman } from '@/api/http';
1313
import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
1414
import TaskDetailsModal from '@/components/server/schedules/TaskDetailsModal';
1515
import { faPencilAlt } from '@fortawesome/free-solid-svg-icons/faPencilAlt';
16+
import Can from '@/components/elements/Can';
1617

1718
interface Props {
1819
schedule: number;
@@ -75,22 +76,26 @@ export default ({ schedule, task, onTaskUpdated, onTaskRemoved }: Props) => {
7576
</p>
7677
</div>
7778
}
78-
<button
79-
type={'button'}
80-
aria-label={'Edit scheduled task'}
81-
className={'block text-sm p-2 text-neutral-500 hover:text-neutral-100 transition-colors duration-150 mr-4'}
82-
onClick={() => setIsEditing(true)}
83-
>
84-
<FontAwesomeIcon icon={faPencilAlt}/>
85-
</button>
86-
<button
87-
type={'button'}
88-
aria-label={'Delete scheduled task'}
89-
className={'block text-sm p-2 text-neutral-500 hover:text-red-600 transition-colors duration-150'}
90-
onClick={() => setVisible(true)}
91-
>
92-
<FontAwesomeIcon icon={faTrashAlt}/>
93-
</button>
79+
<Can action={'schedule.update'}>
80+
<button
81+
type={'button'}
82+
aria-label={'Edit scheduled task'}
83+
className={'block text-sm p-2 text-neutral-500 hover:text-neutral-100 transition-colors duration-150 mr-4'}
84+
onClick={() => setIsEditing(true)}
85+
>
86+
<FontAwesomeIcon icon={faPencilAlt}/>
87+
</button>
88+
</Can>
89+
<Can action={'schedule.update'}>
90+
<button
91+
type={'button'}
92+
aria-label={'Delete scheduled task'}
93+
className={'block text-sm p-2 text-neutral-500 hover:text-red-600 transition-colors duration-150'}
94+
onClick={() => setVisible(true)}
95+
>
96+
<FontAwesomeIcon icon={faTrashAlt}/>
97+
</button>
98+
</Can>
9499
</div>
95100
);
96101
};

0 commit comments

Comments
 (0)