@truedat/audit 4.43.2 → 4.43.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,10 +2,18 @@ import _ from "lodash/fp";
2
2
  import React, { Suspense, useState } from "react";
3
3
  import PropTypes from "prop-types";
4
4
  import { useIntl } from "react-intl";
5
- import { useForm, Controller } from "react-hook-form";
5
+ import { useForm, useWatch, Controller } from "react-hook-form";
6
6
  import { Button, Form, Radio, Icon } from "semantic-ui-react";
7
7
  import { HistoryBackButton } from "@truedat/core/components";
8
- import { events as subscriptionEvents, icons } from "../subscriptionConstants";
8
+ import {
9
+ CONCEPT_EVENTS,
10
+ DEFAULT_ICON,
11
+ EVENTS_BY_TYPE,
12
+ RESOURCE_TYPE_ICONS,
13
+ STATUSES_BY_EVENT,
14
+ SUBSCRIBER_TYPE_ICONS,
15
+ isSubset,
16
+ } from "../subscriptionConstants";
9
17
  import ContentFilters from "./ContentFilters";
10
18
 
11
19
  const ConceptSelector = React.lazy(() =>
@@ -57,12 +65,38 @@ const DEFAULT_VALUES = {
57
65
  },
58
66
  };
59
67
 
68
+ const notEmpty = _.negate(_.isEmpty);
69
+
60
70
  const validFilters = (filters) =>
61
71
  _.conformsTo({
62
72
  template: _.conformsTo({ id: _.isNumber }),
63
73
  content: _.conformsTo({ name: _.isString, value: _.isString }),
64
74
  })(filters);
65
75
 
76
+ const subscriberIcon = (type) =>
77
+ _.getOr(DEFAULT_ICON, type)(SUBSCRIBER_TYPE_ICONS);
78
+ const resourceIcon = (type) => _.getOr(DEFAULT_ICON, type)(RESOURCE_TYPE_ICONS);
79
+ const withoutFilters = ({ filtersEnabled, ...data }) =>
80
+ filtersEnabled &&
81
+ isSubset(data?.scope?.events, CONCEPT_EVENTS) &&
82
+ _.has("scope.filters")(data)
83
+ ? data
84
+ : _.set("scope.filters", null)(data);
85
+ const withResourceName = (resource) => (data) =>
86
+ resource &&
87
+ _.includes(data?.scope?.resource_type)(["data_structure", "source"])
88
+ ? {
89
+ ...data,
90
+ scope: {
91
+ ...data.scope,
92
+ resource_name: resource.name,
93
+ domain_id: resource.domain_id,
94
+ },
95
+ }
96
+ : data;
97
+ const doPayload = (data, resource) =>
98
+ _.flow(withoutFilters, withResourceName(resource))(data);
99
+
66
100
  export const SubscriptionForm = ({
67
101
  onSubmit,
68
102
  subscription = {},
@@ -72,85 +106,69 @@ export const SubscriptionForm = ({
72
106
  const [selectedConceptType, setSelectedConceptType] = useState();
73
107
  const [resource, setResource] = useState();
74
108
 
75
- const { SUBSCRIBER_TYPE_ICONS, DEFAULT_ICON, RESOURCE_TYPE_ICONS } = icons;
76
-
77
- const { handleSubmit, control, formState, setValue, watch } = useForm({
109
+ const { handleSubmit, control, formState, setValue } = useForm({
78
110
  mode: "all",
79
111
  defaultValues: {
80
112
  ...DEFAULT_VALUES,
81
113
  ...subscription,
82
- selectFilters: validFilters(_.path("scope.filters")(subscription)),
114
+ filtersEnabled: validFilters(subscription?.scope?.filters),
83
115
  },
84
116
  });
117
+ const { isDirty, errors } = formState;
85
118
 
86
- const subscriberIcon = (type) =>
87
- _.getOr(DEFAULT_ICON, type)(SUBSCRIBER_TYPE_ICONS);
88
- const resourceIcon = (type) =>
89
- _.getOr(DEFAULT_ICON, type)(RESOURCE_TYPE_ICONS);
90
- const withoutFilters = (state) =>
91
- _.negate(_.has("scope.filters"))(state)
92
- ? _.set("scope.filters", null)(state)
93
- : state;
94
- const withResourceName = (state) =>
95
- _.includes(_.get("scope.resource_type")(state), [
96
- "data_structure",
97
- "source",
98
- ]) && resource
99
- ? {
100
- ...state,
101
- scope: {
102
- ...state.scope,
103
- resource_name: resource.name,
104
- domain_id: resource.domain_id,
105
- },
106
- }
107
- : state;
108
- const doPayload = (state) =>
109
- _.flow(_.omit(["selectFilters"]), withoutFilters, withResourceName)(state);
110
-
111
- const isEditForm = !!_.get("id")(subscription);
112
-
113
- const subscriberType = watch("subscriber.type");
114
- const resourceType = watch("scope.resource_type");
115
- const events = watch("scope.events");
116
- const selectFilters = watch("selectFilters");
119
+ const [subscriberType, resourceType, events] = useWatch({
120
+ control,
121
+ name: ["subscriber.type", "scope.resource_type", "scope.events"],
122
+ });
123
+ const fields = useWatch({ control });
117
124
 
125
+ const isEditForm = !!subscription?.id;
118
126
  const isEmptyEvents = _.isEmpty(events);
119
127
  const isRuleEvent = _.isEqual(["rule_result_created"])(events);
120
- const isConceptEvent =
121
- _.negate(_.isEmpty)(events) &&
122
- _.flow(
123
- _.prop("concept"),
124
- _.map("event"),
125
- _.difference(events),
126
- _.isEmpty
127
- )(subscriptionEvents);
128
-
129
128
  const eventsForType = _.flow(
130
129
  _.getOr([], resourceType),
131
130
  _.filter(
132
- ({ event }) =>
131
+ (event) =>
133
132
  isEmptyEvents ||
134
133
  (isRuleEvent
135
134
  ? event === "rule_result_created"
136
135
  : event !== "rule_result_created")
137
136
  )
138
- )(subscriptionEvents);
137
+ )(EVENTS_BY_TYPE);
139
138
 
140
139
  const statuses = _.flow(
141
- _.filter(({ event }) => _.includes(event)(events)),
142
- _.map("statuses"),
143
- _.reject(_.isNil),
144
- _.flatten,
145
- _.uniq
146
- )(eventsForType);
140
+ _.pick(events),
141
+ _.values,
142
+ _.flatten
143
+ )(STATUSES_BY_EVENT);
147
144
 
148
- const doHandleSubmit = handleSubmit((formState) => {
149
- const payload = doPayload(formState);
145
+ const doHandleSubmit = handleSubmit((data) => {
146
+ const payload = doPayload(data, resource);
150
147
  onSubmit(payload);
151
148
  });
152
149
 
153
- const { isDirty, isValid } = formState;
150
+ const onChangeSubscriberType =
151
+ (onChange) =>
152
+ (_e, { value }) => {
153
+ if (!_.endsWith(value, "role") && !_.endsWith(subscriberType, "role")) {
154
+ setValue("subscriber.identifier", "", { shouldDirty: true });
155
+ }
156
+ if (value === "taxonomy_role" && resourceType !== "domains") {
157
+ setValue("scope.resource_type", "domains", { shouldDirty: true });
158
+ }
159
+
160
+ onChange(value);
161
+ };
162
+
163
+ const onChangeResourceType =
164
+ (onChange) =>
165
+ (_e, { value }) => {
166
+ setSelectedConceptType(null);
167
+ setResource(null);
168
+ onChange(value);
169
+ };
170
+
171
+ const disabled = isLoading || !isDirty || notEmpty(errors);
154
172
 
155
173
  return (
156
174
  <Suspense fallback={null}>
@@ -159,7 +177,7 @@ export const SubscriptionForm = ({
159
177
  control={control}
160
178
  name="subscriber.type"
161
179
  rules={{ required: true }}
162
- render={({ onBlur, onChange, value }) => (
180
+ render={({ field: { onBlur, onChange, value } }) => (
163
181
  <Form.Field className="subscription-form-radio-group" required>
164
182
  <label>{formatMessage({ id: "subscriptions.subscriber" })}</label>
165
183
  {SUBSCRIBER_TYPES.map((type, idx) => (
@@ -179,15 +197,7 @@ export const SubscriptionForm = ({
179
197
  name={type}
180
198
  value={type}
181
199
  checked={value == type}
182
- onChange={(_e, { value }) => {
183
- if (value === "taxonomy_role" && resourceType !== "domains")
184
- setValue("scope.resource_type", "domains", {
185
- shouldValidate: true,
186
- shouldDirty: true,
187
- });
188
-
189
- onChange(value);
190
- }}
200
+ onChange={onChangeSubscriberType(onChange)}
191
201
  />
192
202
  ))}
193
203
  </Form.Field>
@@ -198,10 +208,13 @@ export const SubscriptionForm = ({
198
208
  control={control}
199
209
  name="subscriber.identifier"
200
210
  rules={{ required: true }}
201
- render={({ onBlur, onChange, value }, { invalid }) => (
211
+ render={({
212
+ field: { onBlur, onChange, value },
213
+ fieldState: { error },
214
+ }) => (
202
215
  <RoleSelector
203
216
  disabled={isEditForm}
204
- error={invalid}
217
+ error={!!error}
205
218
  onBlur={onBlur}
206
219
  onChange={(_e, { value }) => onChange(value)}
207
220
  value={value}
@@ -213,14 +226,18 @@ export const SubscriptionForm = ({
213
226
  <Controller
214
227
  control={control}
215
228
  name="subscriber.identifier"
229
+ shouldUnregister
216
230
  rules={{
217
231
  required: true,
218
232
  pattern: { value: /^\S+@\S+\.\S+$/ },
219
233
  }}
220
- render={({ onBlur, onChange, value }, { invalid }) => (
234
+ render={({
235
+ field: { onBlur, onChange, value },
236
+ fieldState: { error },
237
+ }) => (
221
238
  <Form.Input
222
239
  disabled={isEditForm}
223
- error={invalid}
240
+ error={!!error}
224
241
  onBlur={onBlur}
225
242
  onChange={(_e, { value }) => onChange(value)}
226
243
  value={value}
@@ -234,10 +251,13 @@ export const SubscriptionForm = ({
234
251
  control={control}
235
252
  name="subscriber.identifier"
236
253
  rules={{ required: true }}
237
- render={({ onBlur, onChange, value }, { invalid }) => (
254
+ render={({
255
+ field: { onBlur, onChange, value },
256
+ fieldState: { error },
257
+ }) => (
238
258
  <UserSelector
239
259
  disabled={isEditForm}
240
- error={invalid}
260
+ error={!!error}
241
261
  onBlur={onBlur}
242
262
  onChange={(_e, { value }) => onChange(value)}
243
263
  value={value}
@@ -249,7 +269,7 @@ export const SubscriptionForm = ({
249
269
  control={control}
250
270
  name="scope.resource_type"
251
271
  rules={{ required: true }}
252
- render={({ onBlur, onChange, value }) => (
272
+ render={({ field: { onBlur, onChange, value } }) => (
253
273
  <Form.Field className="subscription-form-radio-group" required>
254
274
  <label>{formatMessage({ id: "subscriptions.resource" })}</label>
255
275
  {RESOURCE_TYPES.map((type, idx) => (
@@ -276,11 +296,7 @@ export const SubscriptionForm = ({
276
296
  }
277
297
  value={type}
278
298
  checked={value == type}
279
- onChange={(_e, { value }) => {
280
- setSelectedConceptType(null);
281
- setResource(null);
282
- onChange(value);
283
- }}
299
+ onChange={onChangeResourceType(onChange)}
284
300
  />
285
301
  ))}
286
302
  </Form.Field>
@@ -294,7 +310,7 @@ export const SubscriptionForm = ({
294
310
  control={control}
295
311
  name="scope.resource_id"
296
312
  rules={{ required: true }}
297
- render={({ onChange, value }) => (
313
+ render={({ field: { onChange, value } }) => (
298
314
  <ConceptSelector
299
315
  showTitle={false}
300
316
  handleConceptSelected={(concept) => {
@@ -311,7 +327,7 @@ export const SubscriptionForm = ({
311
327
  control={control}
312
328
  name="scope.resource_id"
313
329
  rules={{ required: true }}
314
- render={({ onChange, value }) => (
330
+ render={({ field: { onChange, value } }) => (
315
331
  <DomainDropdownSelector
316
332
  disabled={isEditForm}
317
333
  value={value}
@@ -326,7 +342,7 @@ export const SubscriptionForm = ({
326
342
  control={control}
327
343
  name="scope.resource_id"
328
344
  rules={{ required: true }}
329
- render={({ onChange }) => (
345
+ render={({ field: { onChange } }) => (
330
346
  <StructureSelector
331
347
  onSelect={({ id, name, domain_id }) => {
332
348
  onChange(id);
@@ -341,7 +357,7 @@ export const SubscriptionForm = ({
341
357
  control={control}
342
358
  name="scope.resource_id"
343
359
  rules={{ required: true }}
344
- render={({ onChange, value }) => (
360
+ render={({ field: { onChange, value } }) => (
345
361
  <SourceSelector
346
362
  disabled={isEditForm}
347
363
  value={value}
@@ -360,9 +376,12 @@ export const SubscriptionForm = ({
360
376
  control={control}
361
377
  name="periodicity"
362
378
  rules={{ required: true }}
363
- render={({ onBlur, onChange, value }, { invalid }) => (
379
+ render={({
380
+ field: { onBlur, onChange, value },
381
+ fieldState: { error },
382
+ }) => (
364
383
  <Form.Dropdown
365
- error={invalid}
384
+ error={!!error}
366
385
  selection
367
386
  clearable
368
387
  label={formatMessage({ id: "subscriptions.periodicity" })}
@@ -388,13 +407,14 @@ export const SubscriptionForm = ({
388
407
  name="scope.events"
389
408
  rules={{
390
409
  required: true,
391
- validate: {
392
- notEmpty: _.negate(_.isEmpty),
393
- },
410
+ validate: { notEmpty },
394
411
  }}
395
- render={({ onBlur, onChange, value }, { invalid }) => (
412
+ render={({
413
+ field: { onBlur, onChange, value },
414
+ fieldState: { error },
415
+ }) => (
396
416
  <Form.Dropdown
397
- error={invalid}
417
+ error={!!error}
398
418
  selection
399
419
  clearable
400
420
  multiple
@@ -402,57 +422,37 @@ export const SubscriptionForm = ({
402
422
  label={formatMessage({ id: "subscriptions.events" })}
403
423
  onBlur={onBlur}
404
424
  onChange={(_e, { value }) => onChange(value)}
405
- placeholder={formatMessage({
406
- id: "subscriptions.events",
407
- })}
425
+ placeholder={formatMessage({ id: "subscriptions.events" })}
408
426
  value={value}
409
427
  required
410
- options={eventsForType.map(({ event }, key) => ({
428
+ options={eventsForType.map((event, key) => ({
411
429
  key,
412
430
  value: event,
413
- text: formatMessage({
414
- id: `subscriptions.events.${event}`,
415
- }),
431
+ text: formatMessage({ id: `subscriptions.events.${event}` }),
416
432
  }))}
417
433
  />
418
434
  )}
419
435
  />
420
- {isConceptEvent && (
421
- <Controller
422
- control={control}
423
- name="selectFilters"
424
- render={({ onChange, value }) => (
425
- <Form.Radio
426
- checked={value}
427
- onChange={(_e, { checked }) => onChange(checked)}
428
- label={formatMessage({ id: "subscriptions.selectFilters" })}
429
- toggle
430
- />
431
- )}
432
- />
433
- )}
434
- {selectFilters && isConceptEvent && (
435
- <ContentFilters
436
- control={control}
437
- setValue={setValue}
438
- watch={watch}
439
- conceptType={selectedConceptType}
440
- />
441
- )}
442
- {!_.isEmpty(statuses) && (
436
+ <ContentFilters
437
+ control={control}
438
+ setValue={setValue}
439
+ conceptType={selectedConceptType}
440
+ />
441
+ {_.isEmpty(statuses) ? null : (
443
442
  <Controller
444
443
  control={control}
445
444
  name="scope.status"
446
445
  rules={{
447
446
  required: true,
448
- validate: {
449
- notEmpty: _.negate(_.isEmpty),
450
- },
447
+ validate: { notEmpty },
451
448
  }}
452
- render={({ onBlur, onChange, value }, { invalid }) => (
449
+ render={({
450
+ field: { onBlur, onChange, value },
451
+ fieldState: { error },
452
+ }) => (
453
453
  <Form.Dropdown
454
454
  onBlur={onBlur}
455
- error={invalid}
455
+ error={!!error}
456
456
  label={formatMessage({ id: "subscriptions.status" })}
457
457
  selection
458
458
  multiple
@@ -460,9 +460,7 @@ export const SubscriptionForm = ({
460
460
  required
461
461
  onChange={(_e, { value }) => onChange(value)}
462
462
  value={value}
463
- placeholder={formatMessage({
464
- id: "subscriptions.status",
465
- })}
463
+ placeholder={formatMessage({ id: "subscriptions.status" })}
466
464
  options={statuses.map(({ name, color }, key) => ({
467
465
  key,
468
466
  value: name,
@@ -485,7 +483,7 @@ export const SubscriptionForm = ({
485
483
  primary
486
484
  type="submit"
487
485
  loading={isLoading}
488
- disabled={isLoading || !isDirty || !isValid}
486
+ disabled={disabled}
489
487
  content={formatMessage({ id: "actions.submit" })}
490
488
  />
491
489
  </div>
@@ -15,7 +15,11 @@ import {
15
15
  Label,
16
16
  Checkbox,
17
17
  } from "semantic-ui-react";
18
- import { icons } from "../subscriptionConstants";
18
+ import {
19
+ DEFAULT_ICON,
20
+ RESOURCE_TYPE_ICONS,
21
+ SUBSCRIBER_TYPE_ICONS,
22
+ } from "../subscriptionConstants";
19
23
 
20
24
  const SUBSCRIBER_TYPES = ["role", "email", "user", "taxonomy_role"];
21
25
  const RESOURCE_TYPES = [
@@ -58,7 +62,6 @@ export const Subscriptions = () => {
58
62
  const { subscriptions, subscriptionsLoading, users } = useSelector(
59
63
  _.pick(["subscriptions", "subscriptionsLoading", "users"])
60
64
  );
61
- const { SUBSCRIBER_TYPE_ICONS, DEFAULT_ICON, RESOURCE_TYPE_ICONS } = icons;
62
65
  if (subscriptionsLoading) return null;
63
66
 
64
67
  const usersById = _.keyBy("id")(users);
@@ -93,7 +96,7 @@ export const Subscriptions = () => {
93
96
  <Controller
94
97
  control={control}
95
98
  name="subscriberTypes"
96
- render={({ onBlur, onChange, value }) => (
99
+ render={({ field: { onBlur, onChange, value } }) => (
97
100
  <Form.Field className="subscriptions-checkbox-filters">
98
101
  <label>
99
102
  <FormattedMessage id="subscriptions.subscriber" />
@@ -126,7 +129,7 @@ export const Subscriptions = () => {
126
129
  <Controller
127
130
  control={control}
128
131
  name="resourceTypes"
129
- render={({ onBlur, onChange, value }) => (
132
+ render={({ field: { onBlur, onChange, value } }) => (
130
133
  <Form.Field className="subscriptions-checkbox-filters">
131
134
  <label>
132
135
  <FormattedMessage id="subscriptions.resource" />