Skip to content

Commit ed01c11

Browse files
authored
Merge pull request #2490 from JohnDuprey/dev
Custom Role Support and Bugfixes
2 parents 1da3471 + 17dcf39 commit ed01c11

File tree

8 files changed

+814
-67
lines changed

8 files changed

+814
-67
lines changed

src/components/forms/RFFComponents.jsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,6 @@ export const RFFCFormRadioList = ({
293293
name,
294294
options,
295295
className = 'mb-3',
296-
disabled = false,
297296
onClick,
298297
inline = false,
299298
}) => {
@@ -312,7 +311,6 @@ export const RFFCFormRadioList = ({
312311
onChange={input.onChange}
313312
type="radio"
314313
{...option}
315-
disabled={disabled}
316314
onClick={onClick}
317315
inline={inline}
318316
/>

src/components/utilities/CippListOffcanvas.jsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ CippListOffcanvas.propTypes = {
3838
hideFunction: PropTypes.func.isRequired,
3939
}
4040

41-
export function OffcanvasListSection({ title, items }) {
41+
export function OffcanvasListSection({ title, items, showCardTitle = true }) {
4242
//console.log(items)
4343
const mappedItems = items.map((item, key) => ({ value: item.content, label: item.heading }))
4444
return (
@@ -48,7 +48,11 @@ export function OffcanvasListSection({ title, items }) {
4848
<CCard className="content-card">
4949
<CCardHeader className="d-flex justify-content-between align-items-center">
5050
<CCardTitle>
51-
<FontAwesomeIcon icon={faGlobe} className="mx-2" /> Extended Information
51+
{showCardTitle && (
52+
<>
53+
<FontAwesomeIcon icon={faGlobe} className="mx-2" /> Extended Information
54+
</>
55+
)}
5256
</CCardTitle>
5357
</CCardHeader>
5458
<CCardBody>
@@ -62,4 +66,5 @@ export function OffcanvasListSection({ title, items }) {
6266
OffcanvasListSection.propTypes = {
6367
title: PropTypes.string,
6468
items: PropTypes.array,
69+
showCardTitle: PropTypes.bool,
6570
}
Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
import React, { useState } from 'react'
2+
import PropTypes from 'prop-types'
3+
import {
4+
CButton,
5+
CCallout,
6+
CCard,
7+
CCardBody,
8+
CCardHeader,
9+
CCol,
10+
CForm,
11+
CRow,
12+
CSpinner,
13+
CTooltip,
14+
} from '@coreui/react'
15+
import { CippOffcanvas, TenantSelector } from '.'
16+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
17+
import { Field, Form, FormSpy } from 'react-final-form'
18+
import arrayMutators from 'final-form-arrays'
19+
import {
20+
RFFCFormInput,
21+
RFFCFormInputArray,
22+
RFFCFormSwitch,
23+
RFFSelectSearch,
24+
} from 'src/components/forms'
25+
import { useSelector } from 'react-redux'
26+
import { useGenericGetRequestQuery, useLazyGenericPostRequestQuery } from 'src/store/api/app'
27+
import DatePicker from 'react-datepicker'
28+
import 'react-datepicker/dist/react-datepicker.css'
29+
30+
export default function CippScheduleOffcanvas({
31+
state: visible,
32+
hideFunction,
33+
title,
34+
placement,
35+
...props
36+
}) {
37+
const currentDate = new Date()
38+
const [startDate, setStartDate] = useState(currentDate)
39+
const tenantDomain = useSelector((state) => state.app.currentTenant.defaultDomainName)
40+
const [refreshState, setRefreshState] = useState(false)
41+
const taskName = `Scheduled Task ${currentDate.toLocaleString()}`
42+
const { data: availableCommands = [], isLoading: isLoadingcmd } = useGenericGetRequestQuery({
43+
path: 'api/ListFunctionParameters?Module=CIPPCore',
44+
})
45+
46+
const recurrenceOptions = [
47+
{ value: '0', name: 'Only once' },
48+
{ value: '1', name: 'Every 1 day' },
49+
{ value: '7', name: 'Every 7 days' },
50+
{ value: '30', name: 'Every 30 days' },
51+
{ value: '365', name: 'Every 365 days' },
52+
]
53+
54+
const [genericPostRequest, postResults] = useLazyGenericPostRequestQuery()
55+
const onSubmit = (values) => {
56+
const unixTime = Math.floor(startDate.getTime() / 1000)
57+
const shippedValues = {
58+
TenantFilter: tenantDomain,
59+
Name: values.taskName,
60+
Command: values.command,
61+
Parameters: values.parameters,
62+
ScheduledTime: unixTime,
63+
Recurrence: values.Recurrence,
64+
AdditionalProperties: values.additional,
65+
PostExecution: {
66+
Webhook: values.webhook,
67+
Email: values.email,
68+
PSA: values.psa,
69+
},
70+
}
71+
genericPostRequest({ path: '/api/AddScheduledItem', values: shippedValues }).then((res) => {
72+
setRefreshState(res.requestId)
73+
if (props.submitFunction) {
74+
props.submitFunction()
75+
}
76+
})
77+
}
78+
79+
return (
80+
<CippOffcanvas
81+
placement={placement}
82+
title={title}
83+
visible={visible}
84+
hideFunction={hideFunction}
85+
>
86+
<CCard>
87+
<CCardHeader></CCardHeader>
88+
<CCardBody>
89+
<Form
90+
onSubmit={onSubmit}
91+
mutators={{
92+
...arrayMutators,
93+
}}
94+
initialValues={{ ...props.initialValues }}
95+
render={({ handleSubmit, submitting, values }) => {
96+
return (
97+
<CForm onSubmit={handleSubmit}>
98+
<CRow className="mb-3">
99+
<CCol>
100+
<label>Tenant</label>
101+
<Field name="tenantFilter">{(props) => <TenantSelector />}</Field>
102+
</CCol>
103+
</CRow>
104+
<CRow>
105+
<CCol>
106+
<RFFCFormInput
107+
type="text"
108+
name="taskName"
109+
label="Task Name"
110+
firstValue={`Task ${currentDate.toLocaleString()}`}
111+
/>
112+
</CCol>
113+
</CRow>
114+
<CRow>
115+
<CCol>
116+
<label>Scheduled Date</label>
117+
<DatePicker
118+
className="form-control mb-3"
119+
selected={startDate}
120+
showTimeSelect
121+
timeFormat="HH:mm"
122+
timeIntervals={15}
123+
dateFormat="Pp"
124+
onChange={(date) => setStartDate(date)}
125+
/>
126+
</CCol>
127+
</CRow>
128+
<CRow className="mb-3">
129+
<CCol>
130+
<RFFSelectSearch
131+
values={recurrenceOptions}
132+
name="Recurrence"
133+
placeholder="Select a recurrence"
134+
label="Recurrence"
135+
/>
136+
</CCol>
137+
</CRow>
138+
<CRow className="mb-3">
139+
<CCol>
140+
<RFFSelectSearch
141+
values={availableCommands.map((cmd) => ({
142+
value: cmd.Function,
143+
name: cmd.Function,
144+
}))}
145+
name="command"
146+
placeholder={
147+
isLoadingcmd ? (
148+
<CSpinner size="sm" />
149+
) : (
150+
'Select a command or report to execute.'
151+
)
152+
}
153+
label="Command to execute"
154+
/>
155+
</CCol>
156+
</CRow>
157+
<FormSpy>
158+
{/* eslint-disable react/prop-types */}
159+
{(props) => {
160+
const selectedCommand = availableCommands.find(
161+
(cmd) => cmd.Function === props.values.command?.value,
162+
)
163+
return (
164+
<CRow className="mb-3">
165+
<CCol>{selectedCommand?.Synopsis}</CCol>
166+
</CRow>
167+
)
168+
}}
169+
</FormSpy>
170+
<CRow>
171+
<FormSpy>
172+
{/* eslint-disable react/prop-types */}
173+
{(props) => {
174+
const selectedCommand = availableCommands.find(
175+
(cmd) => cmd.Function === props.values.command?.value,
176+
)
177+
let paramblock = null
178+
if (selectedCommand) {
179+
//if the command parameter type is boolean we use <RFFCFormCheck /> else <RFFCFormInput />.
180+
const parameters = selectedCommand.Parameters
181+
if (parameters.length > 0) {
182+
paramblock = parameters.map((param, idx) => (
183+
<CRow key={idx} className="mb-3">
184+
<CTooltip
185+
content={
186+
param?.Description !== null
187+
? param.Description
188+
: 'No Description'
189+
}
190+
placement="left"
191+
>
192+
<CCol>
193+
{param.Type === 'System.Boolean' ||
194+
param.Type ===
195+
'System.Management.Automation.SwitchParameter' ? (
196+
<>
197+
<label>{param.Name}</label>
198+
<RFFCFormSwitch
199+
initialValue={false}
200+
name={`parameters.${param.Name}`}
201+
label={`True`}
202+
/>
203+
</>
204+
) : (
205+
<>
206+
{param.Type === 'System.Collections.Hashtable' ? (
207+
<RFFCFormInputArray
208+
name={`parameters.${param.Name}`}
209+
label={`${param.Name}`}
210+
key={idx}
211+
/>
212+
) : (
213+
<RFFCFormInput
214+
type="text"
215+
key={idx}
216+
name={`parameters.${param.Name}`}
217+
label={`${param.Name}`}
218+
/>
219+
)}
220+
</>
221+
)}
222+
</CCol>
223+
</CTooltip>
224+
</CRow>
225+
))
226+
}
227+
}
228+
return paramblock
229+
}}
230+
</FormSpy>
231+
</CRow>
232+
<CRow className="mb-3">
233+
<CCol>
234+
<RFFCFormInputArray name={`additional`} label="Additional Properties" />
235+
</CCol>
236+
</CRow>
237+
<CRow className="mb-3">
238+
<CCol>
239+
<label>Send results to</label>
240+
<RFFCFormSwitch name="webhook" label="Webhook" />
241+
<RFFCFormSwitch name="email" label="E-mail" />
242+
<RFFCFormSwitch name="psa" label="PSA" />
243+
</CCol>
244+
</CRow>
245+
<CRow className="mb-3">
246+
<CCol md={6}>
247+
<CButton type="submit" disabled={submitting}>
248+
Add Schedule
249+
{postResults.isFetching && (
250+
<FontAwesomeIcon icon="circle-notch" spin className="ms-2" size="1x" />
251+
)}
252+
</CButton>
253+
</CCol>
254+
</CRow>
255+
{postResults.isSuccess && (
256+
<CCallout color="success">
257+
<li>{postResults.data.Results}</li>
258+
</CCallout>
259+
)}
260+
</CForm>
261+
)
262+
}}
263+
/>
264+
</CCardBody>
265+
</CCard>
266+
</CippOffcanvas>
267+
)
268+
}
269+
270+
CippScheduleOffcanvas.propTypes = {
271+
groups: PropTypes.array,
272+
placement: PropTypes.string.isRequired,
273+
title: PropTypes.string.isRequired,
274+
state: PropTypes.bool,
275+
hideFunction: PropTypes.func.isRequired,
276+
}

src/views/cipp/Scheduler.jsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,6 @@ const Scheduler = () => {
157157
if (typeof row?.Parameters[key] === 'object') {
158158
var nestedParamList = []
159159
Object.keys(row?.Parameters[key]).forEach((nestedKey) => {
160-
console.log(nestedKey)
161160
nestedParamList.push({
162161
Key: nestedKey,
163162
Value: row?.Parameters[key][nestedKey],

src/views/cipp/app-settings/SettingsExtensionMappings.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,7 @@ export function SettingsExtensionMappings() {
337337
onClick={() => {
338338
if (
339339
mappingValue.value !== undefined &&
340+
mappingValue.value !== '-1' &&
340341
Object.values(haloMappingsArray)
341342
.map((item) => item.haloId)
342343
.includes(mappingValue.value) === false
@@ -481,6 +482,7 @@ export function SettingsExtensionMappings() {
481482
//set the new mapping in the array
482483
if (
483484
mappingValue.value !== undefined &&
485+
mappingValue.value !== '-1' &&
484486
Object.values(ninjaMappingsArray)
485487
.map((item) => item.ninjaId)
486488
.includes(mappingValue.value) === false

0 commit comments

Comments
 (0)