@webiny/webhooks 6.4.0-beta.3 → 6.4.0-beta.5

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.
Files changed (142) hide show
  1. package/admin/WebhookRoutes.js +13 -2
  2. package/admin/WebhookRoutes.js.map +1 -1
  3. package/admin/Webhooks.js +0 -3
  4. package/admin/Webhooks.js.map +1 -1
  5. package/admin/features/getWebhookSettings/GetWebhookSettingsGateway.js +1 -0
  6. package/admin/features/getWebhookSettings/GetWebhookSettingsGateway.js.map +1 -1
  7. package/admin/features/listWebhookDeliveries/ListWebhookDeliveriesGateway.js +1 -1
  8. package/admin/features/listWebhookDeliveries/ListWebhookDeliveriesGateway.js.map +1 -1
  9. package/admin/features/listWebhookDeliveries/abstractions.d.ts +6 -1
  10. package/admin/features/listWebhookDeliveries/abstractions.js.map +1 -1
  11. package/admin/features/updateWebhookSettings/UpdateWebhookSettingsGateway.js +1 -0
  12. package/admin/features/updateWebhookSettings/UpdateWebhookSettingsGateway.js.map +1 -1
  13. package/admin/features/updateWebhookSettings/abstractions.d.ts +1 -0
  14. package/admin/features/updateWebhookSettings/abstractions.js.map +1 -1
  15. package/admin/presentation/{WebhookDeliveries → WebhookDeliveriesPage}/WebhookDeliveriesDataSource.d.ts +1 -2
  16. package/admin/presentation/{WebhookDeliveries → WebhookDeliveriesPage}/WebhookDeliveriesDataSource.js +5 -7
  17. package/admin/presentation/WebhookDeliveriesPage/WebhookDeliveriesDataSource.js.map +1 -0
  18. package/admin/presentation/WebhookDeliveriesPage/WebhookDeliveriesPagePresenter.d.ts +41 -0
  19. package/admin/presentation/WebhookDeliveriesPage/WebhookDeliveriesPagePresenter.js +223 -0
  20. package/admin/presentation/WebhookDeliveriesPage/WebhookDeliveriesPagePresenter.js.map +1 -0
  21. package/admin/presentation/WebhookDeliveriesPage/abstractions.d.ts +42 -0
  22. package/admin/presentation/WebhookDeliveriesPage/abstractions.js +5 -0
  23. package/admin/presentation/WebhookDeliveriesPage/abstractions.js.map +1 -0
  24. package/admin/presentation/WebhookDeliveriesPage/components/DeliveryAccordionRow.d.ts +11 -0
  25. package/admin/presentation/WebhookDeliveriesPage/components/DeliveryAccordionRow.js +36 -0
  26. package/admin/presentation/WebhookDeliveriesPage/components/DeliveryAccordionRow.js.map +1 -0
  27. package/admin/presentation/WebhookDeliveriesPage/components/DeliveryBottomInfoBar.d.ts +9 -0
  28. package/admin/presentation/WebhookDeliveriesPage/components/DeliveryBottomInfoBar.js +43 -0
  29. package/admin/presentation/WebhookDeliveriesPage/components/DeliveryBottomInfoBar.js.map +1 -0
  30. package/admin/presentation/WebhookDeliveriesPage/components/DeliveryDetailContent.d.ts +7 -0
  31. package/admin/presentation/WebhookDeliveriesPage/components/DeliveryDetailContent.js +76 -0
  32. package/admin/presentation/WebhookDeliveriesPage/components/DeliveryDetailContent.js.map +1 -0
  33. package/admin/presentation/WebhookDeliveriesPage/components/DeliveryFilters.d.ts +9 -0
  34. package/admin/presentation/WebhookDeliveriesPage/components/DeliveryFilters.js +85 -0
  35. package/admin/presentation/WebhookDeliveriesPage/components/DeliveryFilters.js.map +1 -0
  36. package/admin/presentation/WebhookDeliveriesPage/components/DeliveryList.d.ts +9 -0
  37. package/admin/presentation/WebhookDeliveriesPage/components/DeliveryList.js +61 -0
  38. package/admin/presentation/WebhookDeliveriesPage/components/DeliveryList.js.map +1 -0
  39. package/admin/presentation/WebhookDeliveriesPage/components/WebhookDefinitionsButton.d.ts +2 -0
  40. package/admin/presentation/WebhookDeliveriesPage/components/WebhookDefinitionsButton.js +16 -0
  41. package/admin/presentation/WebhookDeliveriesPage/components/WebhookDefinitionsButton.js.map +1 -0
  42. package/admin/presentation/WebhookDeliveriesPage/components/WebhookDeliveriesPage.d.ts +2 -0
  43. package/admin/presentation/WebhookDeliveriesPage/components/WebhookDeliveriesPage.js +73 -0
  44. package/admin/presentation/WebhookDeliveriesPage/components/WebhookDeliveriesPage.js.map +1 -0
  45. package/admin/presentation/WebhookDeliveriesPage/components/statusVariant.d.ts +1 -0
  46. package/admin/presentation/WebhookDeliveriesPage/components/statusVariant.js +13 -0
  47. package/admin/presentation/WebhookDeliveriesPage/components/statusVariant.js.map +1 -0
  48. package/admin/presentation/WebhookDeliveriesPage/feature.d.ts +3 -0
  49. package/admin/presentation/WebhookDeliveriesPage/feature.js +17 -0
  50. package/admin/presentation/WebhookDeliveriesPage/feature.js.map +1 -0
  51. package/admin/presentation/WebhookDeliveriesPage/index.d.ts +5 -0
  52. package/admin/presentation/WebhookDeliveriesPage/index.js +1 -0
  53. package/admin/presentation/WebhookForm/WebhookFormPresenter.d.ts +6 -6
  54. package/admin/presentation/WebhookForm/WebhookFormPresenter.js +83 -72
  55. package/admin/presentation/WebhookForm/WebhookFormPresenter.js.map +1 -1
  56. package/admin/presentation/WebhookForm/abstractions.d.ts +2 -9
  57. package/admin/presentation/WebhookForm/abstractions.js.map +1 -1
  58. package/admin/presentation/WebhookForm/components/SigningSecret.d.ts +5 -2
  59. package/admin/presentation/WebhookForm/components/SigningSecret.js +7 -3
  60. package/admin/presentation/WebhookForm/components/SigningSecret.js.map +1 -1
  61. package/admin/presentation/WebhookForm/components/WebhookFormView.js +49 -35
  62. package/admin/presentation/WebhookForm/components/WebhookFormView.js.map +1 -1
  63. package/admin/presentation/WebhookList/WebhookListPresenter.d.ts +26 -2
  64. package/admin/presentation/WebhookList/WebhookListPresenter.js +36 -34
  65. package/admin/presentation/WebhookList/WebhookListPresenter.js.map +1 -1
  66. package/admin/presentation/WebhookList/abstractions.d.ts +25 -7
  67. package/admin/presentation/WebhookList/abstractions.js.map +1 -1
  68. package/admin/presentation/WebhookList/components/CreateWebhookButton.d.ts +2 -0
  69. package/admin/presentation/WebhookList/components/CreateWebhookButton.js +22 -0
  70. package/admin/presentation/WebhookList/components/CreateWebhookButton.js.map +1 -0
  71. package/admin/presentation/WebhookList/components/WebhookDeliveriesButton.d.ts +2 -0
  72. package/admin/presentation/WebhookList/components/WebhookDeliveriesButton.js +16 -0
  73. package/admin/presentation/WebhookList/components/WebhookDeliveriesButton.js.map +1 -0
  74. package/admin/presentation/WebhookList/components/WebhookListContent.d.ts +9 -0
  75. package/admin/presentation/WebhookList/components/WebhookListContent.js +170 -0
  76. package/admin/presentation/WebhookList/components/WebhookListContent.js.map +1 -0
  77. package/admin/presentation/WebhookList/components/WebhookListView.js +10 -140
  78. package/admin/presentation/WebhookList/components/WebhookListView.js.map +1 -1
  79. package/admin/presentation/WebhookSettings/WebhookSettingsPresenter.js +14 -6
  80. package/admin/presentation/WebhookSettings/WebhookSettingsPresenter.js.map +1 -1
  81. package/admin/routes.d.ts +4 -1
  82. package/admin/routes.js +11 -4
  83. package/admin/routes.js.map +1 -1
  84. package/admin/shared/types.d.ts +1 -0
  85. package/api/domain/WebhookDelivery.d.ts +0 -1
  86. package/api/domain/WebhookSettings.d.ts +1 -0
  87. package/api/domain/constants.d.ts +1 -1
  88. package/api/domain/constants.js +2 -2
  89. package/api/domain/constants.js.map +1 -1
  90. package/api/features/CreateWebhookDelivery/CreateWebhookDeliveryRepository.d.ts +1 -1
  91. package/api/features/CreateWebhookDelivery/CreateWebhookDeliveryRepository.js +3 -1
  92. package/api/features/CreateWebhookDelivery/CreateWebhookDeliveryRepository.js.map +1 -1
  93. package/api/features/CreateWebhookDelivery/abstractions.d.ts +1 -1
  94. package/api/features/CreateWebhookDelivery/abstractions.js.map +1 -1
  95. package/api/features/GetWebhookSettings/GetWebhookSettingsRepository.js +4 -2
  96. package/api/features/GetWebhookSettings/GetWebhookSettingsRepository.js.map +1 -1
  97. package/api/features/ResendWebhookDelivery/ResendWebhookDeliveryUseCase.d.ts +3 -1
  98. package/api/features/ResendWebhookDelivery/ResendWebhookDeliveryUseCase.js +9 -4
  99. package/api/features/ResendWebhookDelivery/ResendWebhookDeliveryUseCase.js.map +1 -1
  100. package/api/features/SendWebhookTask/SendWebhookTask.d.ts +1 -1
  101. package/api/features/SendWebhookTask/SendWebhookTask.js +1 -1
  102. package/api/features/SendWebhookTask/SendWebhookTask.js.map +1 -1
  103. package/api/features/TriggerWebhook/TriggerWebhookUseCase.d.ts +3 -1
  104. package/api/features/TriggerWebhook/TriggerWebhookUseCase.js +9 -4
  105. package/api/features/TriggerWebhook/TriggerWebhookUseCase.js.map +1 -1
  106. package/api/features/UpdateWebhookSettings/UpdateWebhookSettingsRepository.js +4 -2
  107. package/api/features/UpdateWebhookSettings/UpdateWebhookSettingsRepository.js.map +1 -1
  108. package/api/features/UpdateWebhookSettings/abstractions.d.ts +1 -0
  109. package/api/features/UpdateWebhookSettings/abstractions.js.map +1 -1
  110. package/api/features/UpdateWebhookSettings/schema.d.ts +1 -0
  111. package/api/features/UpdateWebhookSettings/schema.js +3 -1
  112. package/api/features/UpdateWebhookSettings/schema.js.map +1 -1
  113. package/api/features/WebhookDispatcher/WebhookDispatcher.d.ts +3 -1
  114. package/api/features/WebhookDispatcher/WebhookDispatcher.js +9 -4
  115. package/api/features/WebhookDispatcher/WebhookDispatcher.js.map +1 -1
  116. package/api/graphql/WebhookDeliverySchema.js +12 -8
  117. package/api/graphql/WebhookDeliverySchema.js.map +1 -1
  118. package/api/graphql/WebhookEventSchema.js +1 -0
  119. package/api/graphql/WebhookEventSchema.js.map +1 -1
  120. package/api/graphql/WebhookSettingsSchema.js +2 -0
  121. package/api/graphql/WebhookSettingsSchema.js.map +1 -1
  122. package/api/models/WebhookSettingsModel.js +3 -2
  123. package/api/models/WebhookSettingsModel.js.map +1 -1
  124. package/package.json +24 -22
  125. package/admin/presentation/WebhookDeliveries/WebhookDeliveriesDataSource.js.map +0 -1
  126. package/admin/presentation/WebhookDeliveries/WebhookDeliveriesPresenter.d.ts +0 -19
  127. package/admin/presentation/WebhookDeliveries/WebhookDeliveriesPresenter.js +0 -77
  128. package/admin/presentation/WebhookDeliveries/WebhookDeliveriesPresenter.js.map +0 -1
  129. package/admin/presentation/WebhookDeliveries/abstractions.d.ts +0 -22
  130. package/admin/presentation/WebhookDeliveries/abstractions.js +0 -5
  131. package/admin/presentation/WebhookDeliveries/abstractions.js.map +0 -1
  132. package/admin/presentation/WebhookDeliveries/components/DeliveryDetail.d.ts +0 -11
  133. package/admin/presentation/WebhookDeliveries/components/DeliveryDetail.js +0 -73
  134. package/admin/presentation/WebhookDeliveries/components/DeliveryDetail.js.map +0 -1
  135. package/admin/presentation/WebhookDeliveries/components/WebhookDeliveriesDrawer.d.ts +0 -8
  136. package/admin/presentation/WebhookDeliveries/components/WebhookDeliveriesDrawer.js +0 -119
  137. package/admin/presentation/WebhookDeliveries/components/WebhookDeliveriesDrawer.js.map +0 -1
  138. package/admin/presentation/WebhookDeliveries/feature.d.ts +0 -3
  139. package/admin/presentation/WebhookDeliveries/feature.js +0 -17
  140. package/admin/presentation/WebhookDeliveries/feature.js.map +0 -1
  141. package/admin/presentation/WebhookDeliveries/index.d.ts +0 -2
  142. package/admin/presentation/WebhookDeliveries/index.js +0 -2
@@ -0,0 +1,3 @@
1
+ export declare const WebhookDeliveriesPagePresenterFeature: import("@webiny/feature/admin").FeatureDefinition<{
2
+ presenter: import("./abstractions.js").IWebhookDeliveriesPagePresenter;
3
+ }, []>;
@@ -0,0 +1,17 @@
1
+ import { createFeature } from "@webiny/feature/admin";
2
+ import { WebhookDeliveriesPagePresenter } from "./abstractions.js";
3
+ import { WebhookDeliveriesPagePresenter as external_WebhookDeliveriesPagePresenter_js_WebhookDeliveriesPagePresenter } from "./WebhookDeliveriesPagePresenter.js";
4
+ const WebhookDeliveriesPagePresenterFeature = createFeature({
5
+ name: "Webhooks/WebhookDeliveriesPagePresenter",
6
+ register (container) {
7
+ container.register(external_WebhookDeliveriesPagePresenter_js_WebhookDeliveriesPagePresenter).inSingletonScope();
8
+ },
9
+ resolve (container) {
10
+ return {
11
+ presenter: container.resolve(WebhookDeliveriesPagePresenter)
12
+ };
13
+ }
14
+ });
15
+ export { WebhookDeliveriesPagePresenterFeature };
16
+
17
+ //# sourceMappingURL=feature.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin/presentation/WebhookDeliveriesPage/feature.js","sources":["../../../../src/admin/presentation/WebhookDeliveriesPage/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/admin\";\nimport { WebhookDeliveriesPagePresenter as PresenterAbstraction } from \"./abstractions.js\";\nimport { WebhookDeliveriesPagePresenter } from \"./WebhookDeliveriesPagePresenter.js\";\n\nexport const WebhookDeliveriesPagePresenterFeature = createFeature({\n name: \"Webhooks/WebhookDeliveriesPagePresenter\",\n register(container) {\n container.register(WebhookDeliveriesPagePresenter).inSingletonScope();\n },\n resolve(container) {\n return { presenter: container.resolve(PresenterAbstraction) };\n }\n});\n"],"names":["WebhookDeliveriesPagePresenterFeature","createFeature","container","WebhookDeliveriesPagePresenter","PresenterAbstraction"],"mappings":";;;AAIO,MAAMA,wCAAwCC,cAAc;IAC/D,MAAM;IACN,UAASC,SAAS;QACdA,UAAU,QAAQ,CAACC,2EAAgC,gBAAgB;IACvE;IACA,SAAQD,SAAS;QACb,OAAO;YAAE,WAAWA,UAAU,OAAO,CAACE;QAAsB;IAChE;AACJ"}
@@ -0,0 +1,5 @@
1
+ export { WebhookDeliveriesPagePresenterFeature } from "./feature.js";
2
+ export type { IWebhookDeliveriesPagePresenter } from "./abstractions.js";
3
+ export type { IWebhookDeliveriesPageViewModel } from "./abstractions.js";
4
+ export type { IDeliveryPageFilters } from "./abstractions.js";
5
+ export type { IDeliveryFilterOption } from "./abstractions.js";
@@ -0,0 +1 @@
1
+ export { WebhookDeliveriesPagePresenterFeature } from "./feature.js";
@@ -1,4 +1,4 @@
1
- import { type IWebhookFormPresenter, type IWebhookFormViewModel, type IWebhookFormActions } from "./abstractions.js";
1
+ import { type IWebhookFormPresenter, type IWebhookFormViewModel } from "./abstractions.js";
2
2
  import { GetWebhookUseCase } from "../../../admin/features/getWebhook/abstractions.js";
3
3
  import { CreateWebhookUseCase } from "../../../admin/features/createWebhook/abstractions.js";
4
4
  import { UpdateWebhookUseCase } from "../../../admin/features/updateWebhook/abstractions.js";
@@ -18,19 +18,19 @@ declare class WebhookFormPresenterImpl implements IWebhookFormPresenter {
18
18
  private _saving;
19
19
  private _isNew;
20
20
  private _webhook;
21
- private _showDeliveries;
22
21
  private _webhookId;
23
22
  private _form;
24
- private _eventFieldNames;
25
- private _eventGroups;
23
+ private _entityFieldNames;
24
+ private _entityGroups;
26
25
  get vm(): IWebhookFormViewModel;
27
26
  constructor(formModelFactory: FormModelFactory.Interface, getWebhookUseCase: GetWebhookUseCase.Interface, createWebhookUseCase: CreateWebhookUseCase.Interface, updateWebhookUseCase: UpdateWebhookUseCase.Interface, deleteWebhookUseCase: DeleteWebhookUseCase.Interface, listAvailableEventsUseCase: ListAvailableEventsUseCase.Interface, permissions: WebhookPermissions.Interface);
28
27
  private buildForm;
29
- private eventFieldName;
28
+ private entityFieldName;
30
29
  private addEventFields;
31
30
  private collectEvents;
32
31
  private distributeEvents;
33
- actions: IWebhookFormActions;
32
+ save(): Promise<boolean>;
33
+ deleteWebhook(): Promise<void>;
34
34
  init(id: string): Promise<void>;
35
35
  }
36
36
  export declare const WebhookFormPresenter: typeof WebhookFormPresenterImpl & {
@@ -14,7 +14,6 @@ class WebhookFormPresenterImpl {
14
14
  saving: this._saving,
15
15
  isNew: this._isNew,
16
16
  webhook: this._webhook,
17
- showDeliveries: this._showDeliveries,
18
17
  permissions: {
19
18
  canEdit: this.permissions.canEdit("webhook"),
20
19
  canDelete: this.permissions.canDelete("webhook")
@@ -34,55 +33,9 @@ class WebhookFormPresenterImpl {
34
33
  this._saving = false;
35
34
  this._isNew = false;
36
35
  this._webhook = null;
37
- this._showDeliveries = false;
38
36
  this._webhookId = null;
39
- this._eventFieldNames = [];
40
- this._eventGroups = new Map();
41
- this.actions = {
42
- save: async ()=>{
43
- const data = await this._form.submit();
44
- if (false === data) return;
45
- this._saving = true;
46
- try {
47
- const merged = {
48
- name: data.name,
49
- slug: data.slug,
50
- endpointUrl: data.endpointUrl,
51
- description: data.description || void 0,
52
- enabled: data.enabled,
53
- events: this.collectEvents()
54
- };
55
- if (this._isNew) {
56
- const created = await this.createWebhookUseCase.execute(merged);
57
- runInAction(()=>{
58
- this._webhook = created;
59
- this._webhookId = created.id;
60
- this._isNew = false;
61
- this._form.field("slug").setDisabled(true);
62
- });
63
- } else {
64
- const updated = await this.updateWebhookUseCase.execute(this._webhookId, merged);
65
- runInAction(()=>{
66
- this._webhook = updated;
67
- });
68
- }
69
- } finally{
70
- runInAction(()=>{
71
- this._saving = false;
72
- });
73
- }
74
- },
75
- deleteWebhook: async ()=>{
76
- if (!this._webhookId || this._isNew) return;
77
- await this.deleteWebhookUseCase.execute(this._webhookId);
78
- },
79
- openDeliveries: ()=>{
80
- this._showDeliveries = true;
81
- },
82
- closeDeliveries: ()=>{
83
- this._showDeliveries = false;
84
- }
85
- };
37
+ this._entityFieldNames = [];
38
+ this._entityGroups = new Map();
86
39
  this._form = this.buildForm();
87
40
  makeAutoObservable(this, {
88
41
  vm: computed
@@ -108,26 +61,33 @@ class WebhookFormPresenterImpl {
108
61
  ]
109
62
  });
110
63
  }
111
- eventFieldName(app) {
112
- const slug = app.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_|_$/g, "");
64
+ entityFieldName(appLabel, entityLabel) {
65
+ const slug = `${appLabel}_${entityLabel}`.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_|_$/g, "");
113
66
  return `events_${slug}`;
114
67
  }
115
68
  addEventFields(events) {
116
69
  const grouped = new Map();
117
70
  for (const event of events){
118
- const existing = grouped.get(event.appLabel) ?? [];
71
+ let appMap = grouped.get(event.appLabel);
72
+ if (!appMap) {
73
+ appMap = new Map();
74
+ grouped.set(event.appLabel, appMap);
75
+ }
76
+ const existing = appMap.get(event.entityLabel) ?? [];
119
77
  existing.push(event);
120
- grouped.set(event.appLabel, existing);
78
+ appMap.set(event.entityLabel, existing);
121
79
  }
122
- this._eventGroups = grouped;
123
- this._eventFieldNames = [];
80
+ this._entityGroups = grouped;
81
+ this._entityFieldNames = [];
124
82
  this._form.fields((fields)=>{
125
83
  const result = {};
126
- for (const [app, appEvents] of grouped){
127
- const fieldName = this.eventFieldName(app);
128
- this._eventFieldNames.push(fieldName);
129
- result[fieldName] = fields.object().label(app).renderer("objectAccordionSingle").fields((f)=>({
130
- selected: f.text().list().options(appEvents.map((e)=>({
84
+ for (const [appLabel, entities] of grouped)for (const [entityLabel, entityEvents] of entities){
85
+ const fieldName = this.entityFieldName(appLabel, entityLabel);
86
+ this._entityFieldNames.push(fieldName);
87
+ result[fieldName] = fields.object().label(entityLabel).renderer("objectAccordionSingle", {
88
+ open: false
89
+ }).fields((f)=>({
90
+ selected: f.text().list().options(entityEvents.map((e)=>({
131
91
  label: e.label,
132
92
  value: e.eventName
133
93
  }))).renderer("checkboxes")
@@ -135,19 +95,30 @@ class WebhookFormPresenterImpl {
135
95
  }
136
96
  return result;
137
97
  });
138
- this._form.setLayout((layout)=>[
98
+ this._form.setLayout((layout)=>{
99
+ const rows = [
139
100
  layout.row("name", "slug"),
140
101
  layout.row("endpointUrl"),
141
102
  layout.row("description"),
142
- layout.row("enabled"),
143
- layout.separator(),
144
- ...this._eventFieldNames.map((name)=>layout.object(name, (inner)=>[
103
+ layout.row("enabled")
104
+ ];
105
+ for (const [appLabel, entities] of grouped){
106
+ rows.push(layout.separator());
107
+ rows.push(layout.element("sectionHeading", {
108
+ label: appLabel
109
+ }));
110
+ for (const [entityLabel] of entities){
111
+ const fieldName = this.entityFieldName(appLabel, entityLabel);
112
+ rows.push(layout.object(fieldName, (inner)=>[
145
113
  inner.row("selected")
146
- ]))
147
- ]);
114
+ ]));
115
+ }
116
+ }
117
+ return rows;
118
+ });
148
119
  this._form.addRule((form)=>{
149
- if (0 === this._eventFieldNames.length) return [];
150
- for (const fieldName of this._eventFieldNames){
120
+ if (0 === this._entityFieldNames.length) return [];
121
+ for (const fieldName of this._entityFieldNames){
151
122
  const objectField = form.field(fieldName).as("object");
152
123
  const selectedField = objectField.children.get("selected");
153
124
  if (!selectedField) continue;
@@ -164,7 +135,7 @@ class WebhookFormPresenterImpl {
164
135
  }
165
136
  collectEvents() {
166
137
  const allEvents = [];
167
- for (const fieldName of this._eventFieldNames){
138
+ for (const fieldName of this._entityFieldNames){
168
139
  const objectField = this._form.field(fieldName).as("object");
169
140
  const selectedField = objectField.children.get("selected");
170
141
  if (!selectedField) continue;
@@ -175,15 +146,55 @@ class WebhookFormPresenterImpl {
175
146
  }
176
147
  distributeEvents(webhookEvents) {
177
148
  const eventSet = new Set(webhookEvents);
178
- for (const [app, appEvents] of this._eventGroups){
179
- const fieldName = this.eventFieldName(app);
149
+ for (const [appLabel, entities] of this._entityGroups)for (const [entityLabel, entityEvents] of entities){
150
+ const fieldName = this.entityFieldName(appLabel, entityLabel);
180
151
  const objectField = this._form.field(fieldName).as("object");
181
152
  const selectedField = objectField.children.get("selected");
182
153
  if (!selectedField) continue;
183
- const selected = appEvents.filter((e)=>eventSet.has(e.eventName)).map((e)=>e.eventName);
154
+ const selected = entityEvents.filter((e)=>eventSet.has(e.eventName)).map((e)=>e.eventName);
184
155
  selectedField.setValue(selected);
185
156
  }
186
157
  }
158
+ async save() {
159
+ const data = await this._form.submit();
160
+ if (false === data) return false;
161
+ runInAction(()=>{
162
+ this._saving = true;
163
+ });
164
+ try {
165
+ const merged = {
166
+ name: data.name,
167
+ slug: data.slug,
168
+ endpointUrl: data.endpointUrl,
169
+ description: data.description || void 0,
170
+ enabled: data.enabled,
171
+ events: this.collectEvents()
172
+ };
173
+ if (this._isNew) {
174
+ const created = await this.createWebhookUseCase.execute(merged);
175
+ runInAction(()=>{
176
+ this._webhook = created;
177
+ this._webhookId = created.id;
178
+ this._isNew = false;
179
+ this._form.field("slug").setDisabled(true);
180
+ });
181
+ } else {
182
+ const updated = await this.updateWebhookUseCase.execute(this._webhookId, merged);
183
+ runInAction(()=>{
184
+ this._webhook = updated;
185
+ });
186
+ }
187
+ } finally{
188
+ runInAction(()=>{
189
+ this._saving = false;
190
+ });
191
+ }
192
+ return true;
193
+ }
194
+ async deleteWebhook() {
195
+ if (!this._webhookId || this._isNew) return;
196
+ await this.deleteWebhookUseCase.execute(this._webhookId);
197
+ }
187
198
  async init(id) {
188
199
  this._loading = true;
189
200
  this._isNew = "new" === id;
@@ -1 +1 @@
1
- {"version":3,"file":"admin/presentation/WebhookForm/WebhookFormPresenter.js","sources":["../../../../src/admin/presentation/WebhookForm/WebhookFormPresenter.ts"],"sourcesContent":["import { computed, makeAutoObservable, runInAction } from \"mobx\";\nimport type { Webhook } from \"~/admin/shared/types.js\";\nimport type { WebhookEvent } from \"~/admin/shared/types.js\";\nimport {\n WebhookFormPresenter as Abstraction,\n type IWebhookFormPresenter,\n type IWebhookFormViewModel,\n type IWebhookFormActions\n} from \"./abstractions.js\";\nimport { GetWebhookUseCase } from \"~/admin/features/getWebhook/abstractions.js\";\nimport { CreateWebhookUseCase } from \"~/admin/features/createWebhook/abstractions.js\";\nimport { UpdateWebhookUseCase } from \"~/admin/features/updateWebhook/abstractions.js\";\nimport { DeleteWebhookUseCase } from \"~/admin/features/deleteWebhook/abstractions.js\";\nimport { ListAvailableEventsUseCase } from \"~/admin/features/listAvailableEvents/abstractions.js\";\nimport { WebhookPermissions } from \"~/admin/features/permissions/abstractions.js\";\nimport {\n FormModelFactory,\n type IFormModel\n} from \"@webiny/app-admin/features/formModel/abstractions.js\";\n\nclass WebhookFormPresenterImpl implements IWebhookFormPresenter {\n private _loading = false;\n private _saving = false;\n private _isNew = false;\n private _webhook: Webhook | null = null;\n private _showDeliveries = false;\n private _webhookId: string | null = null;\n private _form: IFormModel;\n private _eventFieldNames: string[] = [];\n private _eventGroups: Map<string, WebhookEvent[]> = new Map();\n\n public get vm(): IWebhookFormViewModel {\n return {\n loading: this._loading,\n saving: this._saving,\n isNew: this._isNew,\n webhook: this._webhook,\n showDeliveries: this._showDeliveries,\n permissions: {\n canEdit: this.permissions.canEdit(\"webhook\"),\n canDelete: this.permissions.canDelete(\"webhook\")\n },\n form: this._form.vm\n };\n }\n\n public constructor(\n private readonly formModelFactory: FormModelFactory.Interface,\n private readonly getWebhookUseCase: GetWebhookUseCase.Interface,\n private readonly createWebhookUseCase: CreateWebhookUseCase.Interface,\n private readonly updateWebhookUseCase: UpdateWebhookUseCase.Interface,\n private readonly deleteWebhookUseCase: DeleteWebhookUseCase.Interface,\n private readonly listAvailableEventsUseCase: ListAvailableEventsUseCase.Interface,\n private readonly permissions: WebhookPermissions.Interface\n ) {\n this._form = this.buildForm();\n\n makeAutoObservable(this, { vm: computed });\n }\n\n private buildForm(): IFormModel {\n return this.formModelFactory.create({\n fields: fields => ({\n name: fields.text().label(\"Name\").required(\"Name is required\"),\n slug: fields\n .text()\n .label(\"Slug\")\n .required(\"Slug is required\")\n .computedUntilDirty(form => {\n const name = String(form.field(\"name\").getValue() ?? \"\");\n return name\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9\\s-]/g, \"\")\n .replace(/\\s+/g, \"-\");\n }),\n endpointUrl: fields\n .text()\n .label(\"Endpoint URL\")\n .required(\"Endpoint URL is required\")\n .placeholder(\"https://\"),\n description: fields.text().label(\"Description\").renderer(\"textarea\"),\n enabled: fields.boolean().label(\"Enabled\").defaultValue(false)\n }),\n layout: layout => [\n layout.row(\"name\", \"slug\"),\n layout.row(\"endpointUrl\"),\n layout.row(\"description\"),\n layout.row(\"enabled\")\n ]\n });\n }\n\n private eventFieldName(app: string): string {\n const slug = app\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"_\")\n .replace(/^_|_$/g, \"\");\n return `events_${slug}`;\n }\n\n private addEventFields(events: WebhookEvent[]): void {\n const grouped = new Map<string, WebhookEvent[]>();\n for (const event of events) {\n const existing = grouped.get(event.appLabel) ?? [];\n existing.push(event);\n grouped.set(event.appLabel, existing);\n }\n\n this._eventGroups = grouped;\n this._eventFieldNames = [];\n\n this._form.fields(fields => {\n const result: Record<string, ReturnType<typeof fields.object>> = {};\n\n for (const [app, appEvents] of grouped) {\n const fieldName = this.eventFieldName(app);\n this._eventFieldNames.push(fieldName);\n\n result[fieldName] = fields\n .object()\n .label(app)\n .renderer(\"objectAccordionSingle\")\n .fields(f => {\n return {\n selected: f\n .text()\n .list()\n .options(\n appEvents.map(e => ({\n label: e.label,\n value: e.eventName\n }))\n )\n .renderer(\"checkboxes\")\n };\n });\n }\n\n return result;\n });\n\n this._form.setLayout(layout => [\n layout.row(\"name\", \"slug\"),\n layout.row(\"endpointUrl\"),\n layout.row(\"description\"),\n layout.row(\"enabled\"),\n layout.separator(),\n ...this._eventFieldNames.map(name =>\n layout.object(name, inner => [inner.row(\"selected\")])\n )\n ]);\n\n this._form.addRule(form => {\n if (this._eventFieldNames.length === 0) {\n return [];\n }\n for (const fieldName of this._eventFieldNames) {\n const objectField = form.field(fieldName).as(\"object\");\n const selectedField = objectField.children.get(\"selected\");\n if (!selectedField) {\n continue;\n }\n const values = selectedField.getValue<string[]>();\n if (values && values.length > 0) {\n return [];\n }\n }\n\n return [{ path: \"Events\", message: \"At least one event must be selected.\" }];\n });\n }\n\n private collectEvents(): string[] {\n const allEvents: string[] = [];\n\n for (const fieldName of this._eventFieldNames) {\n const objectField = this._form.field(fieldName).as(\"object\");\n const selectedField = objectField.children.get(\"selected\");\n if (!selectedField) {\n continue;\n }\n const values = selectedField.getValue<string[]>();\n if (values && values.length > 0) {\n allEvents.push(...values);\n }\n }\n\n return allEvents;\n }\n\n private distributeEvents(webhookEvents: string[]): void {\n const eventSet = new Set(webhookEvents);\n\n for (const [app, appEvents] of this._eventGroups) {\n const fieldName = this.eventFieldName(app);\n const objectField = this._form.field(fieldName).as(\"object\");\n const selectedField = objectField.children.get(\"selected\");\n if (!selectedField) {\n continue;\n }\n\n const selected = appEvents.filter(e => eventSet.has(e.eventName)).map(e => e.eventName);\n selectedField.setValue(selected);\n }\n }\n\n public actions: IWebhookFormActions = {\n save: async () => {\n const data = await this._form.submit<Record<string, unknown>>();\n if (data === false) {\n return;\n }\n\n this._saving = true;\n\n try {\n const merged = {\n name: data.name as string,\n slug: data.slug as string,\n endpointUrl: data.endpointUrl as string,\n description: (data.description as string) || undefined,\n enabled: data.enabled as boolean,\n events: this.collectEvents()\n };\n\n if (this._isNew) {\n const created = await this.createWebhookUseCase.execute(merged);\n\n runInAction(() => {\n this._webhook = created;\n this._webhookId = created.id;\n this._isNew = false;\n this._form.field(\"slug\").setDisabled(true);\n });\n } else {\n const updated = await this.updateWebhookUseCase.execute(\n this._webhookId!,\n merged\n );\n\n runInAction(() => {\n this._webhook = updated;\n });\n }\n } finally {\n runInAction(() => {\n this._saving = false;\n });\n }\n },\n deleteWebhook: async () => {\n if (!this._webhookId || this._isNew) {\n return;\n }\n await this.deleteWebhookUseCase.execute(this._webhookId);\n },\n openDeliveries: () => {\n this._showDeliveries = true;\n },\n closeDeliveries: () => {\n this._showDeliveries = false;\n }\n };\n\n public async init(id: string): Promise<void> {\n this._loading = true;\n this._isNew = id === \"new\";\n this._webhookId = id === \"new\" ? null : id;\n\n const eventsPromise = this.listAvailableEventsUseCase.execute();\n\n if (!this._isNew) {\n const [webhook, events] = await Promise.all([\n this.getWebhookUseCase.execute(id),\n eventsPromise\n ]);\n\n runInAction(() => {\n this._webhook = webhook;\n this._form = this.buildForm();\n this.addEventFields(events);\n this._form.setData({\n name: webhook.name,\n slug: webhook.slug,\n endpointUrl: webhook.endpointUrl,\n description: webhook.description ?? \"\",\n enabled: webhook.enabled\n });\n this._form.field(\"slug\").setDisabled(true);\n this.distributeEvents(webhook.events);\n this._loading = false;\n });\n } else {\n const events = await eventsPromise;\n\n runInAction(() => {\n this._form = this.buildForm();\n this.addEventFields(events);\n this._loading = false;\n });\n }\n }\n}\n\nexport const WebhookFormPresenter = Abstraction.createImplementation({\n implementation: WebhookFormPresenterImpl,\n dependencies: [\n FormModelFactory,\n GetWebhookUseCase,\n CreateWebhookUseCase,\n UpdateWebhookUseCase,\n DeleteWebhookUseCase,\n ListAvailableEventsUseCase,\n WebhookPermissions\n ]\n});\n"],"names":["WebhookFormPresenterImpl","formModelFactory","getWebhookUseCase","createWebhookUseCase","updateWebhookUseCase","deleteWebhookUseCase","listAvailableEventsUseCase","permissions","Map","data","merged","undefined","created","runInAction","updated","makeAutoObservable","computed","fields","form","name","String","layout","app","slug","events","grouped","event","existing","result","appEvents","fieldName","f","e","inner","objectField","selectedField","values","allEvents","webhookEvents","eventSet","Set","selected","id","eventsPromise","webhook","Promise","WebhookFormPresenter","Abstraction","FormModelFactory","GetWebhookUseCase","CreateWebhookUseCase","UpdateWebhookUseCase","DeleteWebhookUseCase","ListAvailableEventsUseCase","WebhookPermissions"],"mappings":"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"}
1
+ {"version":3,"file":"admin/presentation/WebhookForm/WebhookFormPresenter.js","sources":["../../../../src/admin/presentation/WebhookForm/WebhookFormPresenter.ts"],"sourcesContent":["import { computed, makeAutoObservable, runInAction } from \"mobx\";\nimport type { Webhook } from \"~/admin/shared/types.js\";\nimport type { WebhookEvent } from \"~/admin/shared/types.js\";\nimport {\n WebhookFormPresenter as Abstraction,\n type IWebhookFormPresenter,\n type IWebhookFormViewModel\n} from \"./abstractions.js\";\nimport { GetWebhookUseCase } from \"~/admin/features/getWebhook/abstractions.js\";\nimport { CreateWebhookUseCase } from \"~/admin/features/createWebhook/abstractions.js\";\nimport { UpdateWebhookUseCase } from \"~/admin/features/updateWebhook/abstractions.js\";\nimport { DeleteWebhookUseCase } from \"~/admin/features/deleteWebhook/abstractions.js\";\nimport { ListAvailableEventsUseCase } from \"~/admin/features/listAvailableEvents/abstractions.js\";\nimport { WebhookPermissions } from \"~/admin/features/permissions/abstractions.js\";\nimport {\n FormModelFactory,\n type IFormModel,\n type ILayoutNodeBuilder\n} from \"@webiny/app-admin/features/formModel/abstractions.js\";\n\nclass WebhookFormPresenterImpl implements IWebhookFormPresenter {\n private _loading = false;\n private _saving = false;\n private _isNew = false;\n private _webhook: Webhook | null = null;\n private _webhookId: string | null = null;\n private _form: IFormModel;\n private _entityFieldNames: string[] = [];\n private _entityGroups: Map<string, Map<string, WebhookEvent[]>> = new Map();\n\n public get vm(): IWebhookFormViewModel {\n return {\n loading: this._loading,\n saving: this._saving,\n isNew: this._isNew,\n webhook: this._webhook,\n permissions: {\n canEdit: this.permissions.canEdit(\"webhook\"),\n canDelete: this.permissions.canDelete(\"webhook\")\n },\n form: this._form.vm\n };\n }\n\n public constructor(\n private readonly formModelFactory: FormModelFactory.Interface,\n private readonly getWebhookUseCase: GetWebhookUseCase.Interface,\n private readonly createWebhookUseCase: CreateWebhookUseCase.Interface,\n private readonly updateWebhookUseCase: UpdateWebhookUseCase.Interface,\n private readonly deleteWebhookUseCase: DeleteWebhookUseCase.Interface,\n private readonly listAvailableEventsUseCase: ListAvailableEventsUseCase.Interface,\n private readonly permissions: WebhookPermissions.Interface\n ) {\n this._form = this.buildForm();\n\n makeAutoObservable(this, { vm: computed });\n }\n\n private buildForm(): IFormModel {\n return this.formModelFactory.create({\n fields: fields => ({\n name: fields.text().label(\"Name\").required(\"Name is required\"),\n slug: fields\n .text()\n .label(\"Slug\")\n .required(\"Slug is required\")\n .computedUntilDirty(form => {\n const name = String(form.field(\"name\").getValue() ?? \"\");\n return name\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9\\s-]/g, \"\")\n .replace(/\\s+/g, \"-\");\n }),\n endpointUrl: fields\n .text()\n .label(\"Endpoint URL\")\n .required(\"Endpoint URL is required\")\n .placeholder(\"https://\"),\n description: fields.text().label(\"Description\").renderer(\"textarea\"),\n enabled: fields.boolean().label(\"Enabled\").defaultValue(false)\n }),\n layout: layout => [\n layout.row(\"name\", \"slug\"),\n layout.row(\"endpointUrl\"),\n layout.row(\"description\"),\n layout.row(\"enabled\")\n ]\n });\n }\n\n private entityFieldName(appLabel: string, entityLabel: string): string {\n const slug = `${appLabel}_${entityLabel}`\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"_\")\n .replace(/^_|_$/g, \"\");\n return `events_${slug}`;\n }\n\n private addEventFields(events: WebhookEvent[]): void {\n const grouped = new Map<string, Map<string, WebhookEvent[]>>();\n for (const event of events) {\n let appMap = grouped.get(event.appLabel);\n if (!appMap) {\n appMap = new Map();\n grouped.set(event.appLabel, appMap);\n }\n const existing = appMap.get(event.entityLabel) ?? [];\n existing.push(event);\n appMap.set(event.entityLabel, existing);\n }\n\n this._entityGroups = grouped;\n this._entityFieldNames = [];\n\n this._form.fields(fields => {\n const result: Record<string, ReturnType<typeof fields.object>> = {};\n\n for (const [appLabel, entities] of grouped) {\n for (const [entityLabel, entityEvents] of entities) {\n const fieldName = this.entityFieldName(appLabel, entityLabel);\n this._entityFieldNames.push(fieldName);\n\n result[fieldName] = fields\n .object()\n .label(entityLabel)\n .renderer(\"objectAccordionSingle\", { open: false })\n .fields(f => {\n return {\n selected: f\n .text()\n .list()\n .options(\n entityEvents.map(e => ({\n label: e.label,\n value: e.eventName\n }))\n )\n .renderer(\"checkboxes\")\n };\n });\n }\n }\n\n return result;\n });\n\n this._form.setLayout(layout => {\n const rows: ILayoutNodeBuilder[] = [\n layout.row(\"name\", \"slug\"),\n layout.row(\"endpointUrl\"),\n layout.row(\"description\"),\n layout.row(\"enabled\")\n ];\n\n for (const [appLabel, entities] of grouped) {\n rows.push(layout.separator());\n rows.push(layout.element(\"sectionHeading\", { label: appLabel }));\n\n for (const [entityLabel] of entities) {\n const fieldName = this.entityFieldName(appLabel, entityLabel);\n rows.push(layout.object(fieldName, inner => [inner.row(\"selected\")]));\n }\n }\n\n return rows;\n });\n\n this._form.addRule(form => {\n if (this._entityFieldNames.length === 0) {\n return [];\n }\n for (const fieldName of this._entityFieldNames) {\n const objectField = form.field(fieldName).as(\"object\");\n const selectedField = objectField.children.get(\"selected\");\n if (!selectedField) {\n continue;\n }\n const values = selectedField.getValue<string[]>();\n if (values && values.length > 0) {\n return [];\n }\n }\n\n return [{ path: \"Events\", message: \"At least one event must be selected.\" }];\n });\n }\n\n private collectEvents(): string[] {\n const allEvents: string[] = [];\n\n for (const fieldName of this._entityFieldNames) {\n const objectField = this._form.field(fieldName).as(\"object\");\n const selectedField = objectField.children.get(\"selected\");\n if (!selectedField) {\n continue;\n }\n const values = selectedField.getValue<string[]>();\n if (values && values.length > 0) {\n allEvents.push(...values);\n }\n }\n\n return allEvents;\n }\n\n private distributeEvents(webhookEvents: string[]): void {\n const eventSet = new Set(webhookEvents);\n\n for (const [appLabel, entities] of this._entityGroups) {\n for (const [entityLabel, entityEvents] of entities) {\n const fieldName = this.entityFieldName(appLabel, entityLabel);\n const objectField = this._form.field(fieldName).as(\"object\");\n const selectedField = objectField.children.get(\"selected\");\n if (!selectedField) {\n continue;\n }\n\n const selected = entityEvents\n .filter(e => eventSet.has(e.eventName))\n .map(e => e.eventName);\n selectedField.setValue(selected);\n }\n }\n }\n\n public async save(): Promise<boolean> {\n const data = await this._form.submit<Record<string, unknown>>();\n if (data === false) {\n return false;\n }\n\n runInAction(() => {\n this._saving = true;\n });\n\n try {\n const merged = {\n name: data.name as string,\n slug: data.slug as string,\n endpointUrl: data.endpointUrl as string,\n description: (data.description as string) || undefined,\n enabled: data.enabled as boolean,\n events: this.collectEvents()\n };\n\n if (this._isNew) {\n const created = await this.createWebhookUseCase.execute(merged);\n\n runInAction(() => {\n this._webhook = created;\n this._webhookId = created.id;\n this._isNew = false;\n this._form.field(\"slug\").setDisabled(true);\n });\n } else {\n const updated = await this.updateWebhookUseCase.execute(this._webhookId!, merged);\n\n runInAction(() => {\n this._webhook = updated;\n });\n }\n } finally {\n runInAction(() => {\n this._saving = false;\n });\n }\n\n return true;\n }\n\n public async deleteWebhook(): Promise<void> {\n if (!this._webhookId || this._isNew) {\n return;\n }\n await this.deleteWebhookUseCase.execute(this._webhookId);\n }\n\n public async init(id: string): Promise<void> {\n this._loading = true;\n this._isNew = id === \"new\";\n this._webhookId = id === \"new\" ? null : id;\n\n const eventsPromise = this.listAvailableEventsUseCase.execute();\n\n if (!this._isNew) {\n const [webhook, events] = await Promise.all([\n this.getWebhookUseCase.execute(id),\n eventsPromise\n ]);\n\n runInAction(() => {\n this._webhook = webhook;\n this._form = this.buildForm();\n this.addEventFields(events);\n this._form.setData({\n name: webhook.name,\n slug: webhook.slug,\n endpointUrl: webhook.endpointUrl,\n description: webhook.description ?? \"\",\n enabled: webhook.enabled\n });\n this._form.field(\"slug\").setDisabled(true);\n this.distributeEvents(webhook.events);\n this._loading = false;\n });\n } else {\n const events = await eventsPromise;\n\n runInAction(() => {\n this._form = this.buildForm();\n this.addEventFields(events);\n this._loading = false;\n });\n }\n }\n}\n\nexport const WebhookFormPresenter = Abstraction.createImplementation({\n implementation: WebhookFormPresenterImpl,\n dependencies: [\n FormModelFactory,\n GetWebhookUseCase,\n CreateWebhookUseCase,\n UpdateWebhookUseCase,\n DeleteWebhookUseCase,\n ListAvailableEventsUseCase,\n WebhookPermissions\n ]\n});\n"],"names":["WebhookFormPresenterImpl","formModelFactory","getWebhookUseCase","createWebhookUseCase","updateWebhookUseCase","deleteWebhookUseCase","listAvailableEventsUseCase","permissions","Map","makeAutoObservable","computed","fields","form","name","String","layout","appLabel","entityLabel","slug","events","grouped","event","appMap","existing","result","entities","entityEvents","fieldName","f","e","rows","inner","objectField","selectedField","values","allEvents","webhookEvents","eventSet","Set","selected","data","runInAction","merged","undefined","created","updated","id","eventsPromise","webhook","Promise","WebhookFormPresenter","Abstraction","FormModelFactory","GetWebhookUseCase","CreateWebhookUseCase","UpdateWebhookUseCase","DeleteWebhookUseCase","ListAvailableEventsUseCase","WebhookPermissions"],"mappings":"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"}
@@ -5,27 +5,20 @@ export interface IWebhookFormViewModel {
5
5
  saving: boolean;
6
6
  isNew: boolean;
7
7
  webhook: Webhook | null;
8
- showDeliveries: boolean;
9
8
  permissions: {
10
9
  canEdit: boolean;
11
10
  canDelete: boolean;
12
11
  };
13
12
  form: IFormVM;
14
13
  }
15
- export interface IWebhookFormActions {
16
- save(): Promise<void>;
17
- deleteWebhook(): Promise<void>;
18
- openDeliveries(): void;
19
- closeDeliveries(): void;
20
- }
21
14
  export interface IWebhookFormPresenter {
22
15
  vm: IWebhookFormViewModel;
23
- actions: IWebhookFormActions;
24
16
  init(id: string): void;
17
+ save(): Promise<boolean>;
18
+ deleteWebhook(): Promise<void>;
25
19
  }
26
20
  export declare const WebhookFormPresenter: import("@webiny/di").Abstraction<IWebhookFormPresenter>;
27
21
  export declare namespace WebhookFormPresenter {
28
22
  type Interface = IWebhookFormPresenter;
29
23
  type ViewModel = IWebhookFormViewModel;
30
- type Actions = IWebhookFormActions;
31
24
  }
@@ -1 +1 @@
1
- {"version":3,"file":"admin/presentation/WebhookForm/abstractions.js","sources":["../../../../src/admin/presentation/WebhookForm/abstractions.ts"],"sourcesContent":["import { createAbstraction } from \"@webiny/feature/admin\";\nimport type { Webhook } from \"~/admin/shared/types.js\";\nimport type { IFormVM } from \"@webiny/app-admin/features/formModel/abstractions.js\";\n\nexport interface IWebhookFormViewModel {\n loading: boolean;\n saving: boolean;\n isNew: boolean;\n webhook: Webhook | null;\n showDeliveries: boolean;\n permissions: {\n canEdit: boolean;\n canDelete: boolean;\n };\n form: IFormVM;\n}\n\nexport interface IWebhookFormActions {\n save(): Promise<void>;\n deleteWebhook(): Promise<void>;\n openDeliveries(): void;\n closeDeliveries(): void;\n}\n\nexport interface IWebhookFormPresenter {\n vm: IWebhookFormViewModel;\n actions: IWebhookFormActions;\n init(id: string): void;\n}\n\nexport const WebhookFormPresenter =\n createAbstraction<IWebhookFormPresenter>(\"WebhookFormPresenter\");\n\nexport namespace WebhookFormPresenter {\n export type Interface = IWebhookFormPresenter;\n export type ViewModel = IWebhookFormViewModel;\n export type Actions = IWebhookFormActions;\n}\n"],"names":["WebhookFormPresenter","createAbstraction"],"mappings":";AA8BO,MAAMA,uBACTC,kBAAyC"}
1
+ {"version":3,"file":"admin/presentation/WebhookForm/abstractions.js","sources":["../../../../src/admin/presentation/WebhookForm/abstractions.ts"],"sourcesContent":["import { createAbstraction } from \"@webiny/feature/admin\";\nimport type { Webhook } from \"~/admin/shared/types.js\";\nimport type { IFormVM } from \"@webiny/app-admin/features/formModel/abstractions.js\";\n\nexport interface IWebhookFormViewModel {\n loading: boolean;\n saving: boolean;\n isNew: boolean;\n webhook: Webhook | null;\n permissions: {\n canEdit: boolean;\n canDelete: boolean;\n };\n form: IFormVM;\n}\n\nexport interface IWebhookFormPresenter {\n vm: IWebhookFormViewModel;\n init(id: string): void;\n save(): Promise<boolean>;\n deleteWebhook(): Promise<void>;\n}\n\nexport const WebhookFormPresenter =\n createAbstraction<IWebhookFormPresenter>(\"WebhookFormPresenter\");\n\nexport namespace WebhookFormPresenter {\n export type Interface = IWebhookFormPresenter;\n export type ViewModel = IWebhookFormViewModel;\n}\n"],"names":["WebhookFormPresenter","createAbstraction"],"mappings":";AAuBO,MAAMA,uBACTC,kBAAyC"}
@@ -1,6 +1,9 @@
1
1
  import React from "react";
2
+ import type { IWebhookFormPresenter } from "../abstractions.js";
2
3
  interface SigningSecretProps {
3
- secret: string;
4
+ presenter: IWebhookFormPresenter;
4
5
  }
5
- export declare const SigningSecret: ({ secret }: SigningSecretProps) => React.JSX.Element;
6
+ export declare const SigningSecret: (({ presenter }: SigningSecretProps) => React.JSX.Element | null) & {
7
+ displayName: string;
8
+ };
6
9
  export {};
@@ -1,12 +1,16 @@
1
1
  import react, { useCallback, useState } from "react";
2
+ import { observer } from "mobx-react-lite";
2
3
  import { IconButton, Text } from "@webiny/admin-ui";
3
4
  import { useSnackbar } from "@webiny/app-admin/hooks/index.js";
4
5
  import { ReactComponent } from "@webiny/icons/visibility.svg";
5
6
  import { ReactComponent as visibility_off_svg_ReactComponent } from "@webiny/icons/visibility_off.svg";
6
7
  import { ReactComponent as content_copy_svg_ReactComponent } from "@webiny/icons/content_copy.svg";
7
- const SigningSecret = ({ secret })=>{
8
+ const SigningSecret_SigningSecret = observer(function({ presenter }) {
9
+ const { vm } = presenter;
8
10
  const [revealed, setRevealed] = useState(false);
9
11
  const { showSnackbar } = useSnackbar();
12
+ if (vm.isNew || !vm.webhook?.signingSecret) return null;
13
+ const secret = vm.webhook.signingSecret;
10
14
  const handleCopy = useCallback(async ()=>{
11
15
  await navigator.clipboard.writeText(secret);
12
16
  showSnackbar("Signing secret copied to clipboard.");
@@ -37,7 +41,7 @@ const SigningSecret = ({ secret })=>{
37
41
  onClick: ()=>void handleCopy(),
38
42
  "aria-label": "Copy secret"
39
43
  })));
40
- };
41
- export { SigningSecret };
44
+ });
45
+ export { SigningSecret_SigningSecret as SigningSecret };
42
46
 
43
47
  //# sourceMappingURL=SigningSecret.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"admin/presentation/WebhookForm/components/SigningSecret.js","sources":["../../../../../src/admin/presentation/WebhookForm/components/SigningSecret.tsx"],"sourcesContent":["import React, { useState, useCallback } from \"react\";\nimport { IconButton, Text } from \"@webiny/admin-ui\";\nimport { useSnackbar } from \"@webiny/app-admin/hooks/index.js\";\nimport { ReactComponent as VisibilityIcon } from \"@webiny/icons/visibility.svg\";\nimport { ReactComponent as VisibilityOffIcon } from \"@webiny/icons/visibility_off.svg\";\nimport { ReactComponent as CopyIcon } from \"@webiny/icons/content_copy.svg\";\n\ninterface SigningSecretProps {\n secret: string;\n}\n\nexport const SigningSecret = ({ secret }: SigningSecretProps) => {\n const [revealed, setRevealed] = useState(false);\n const { showSnackbar } = useSnackbar();\n\n const handleCopy = useCallback(async () => {\n await navigator.clipboard.writeText(secret);\n showSnackbar(\"Signing secret copied to clipboard.\");\n }, [secret, showSnackbar]);\n\n return (\n <div className=\"flex flex-col gap-xs\">\n <Text size=\"sm\" className=\"text-neutral-strong\">\n Signing Secret\n </Text>\n <div className=\"flex items-center gap-sm rounded-sm border-sm border-neutral-muted px-sm py-xs\">\n <Text size=\"sm\" className=\"flex-1 font-mono select-all\">\n {revealed ? secret : \"•\".repeat(24)}\n </Text>\n <IconButton\n icon={revealed ? <VisibilityOffIcon /> : <VisibilityIcon />}\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => setRevealed(prev => !prev)}\n aria-label={revealed ? \"Hide secret\" : \"Reveal secret\"}\n />\n <IconButton\n icon={<CopyIcon />}\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => void handleCopy()}\n aria-label=\"Copy secret\"\n />\n </div>\n </div>\n );\n};\n"],"names":["SigningSecret","secret","revealed","setRevealed","useState","showSnackbar","useSnackbar","handleCopy","useCallback","navigator","Text","IconButton","VisibilityOffIcon","VisibilityIcon","prev","CopyIcon"],"mappings":";;;;;;AAWO,MAAMA,gBAAgB,CAAC,EAAEC,MAAM,EAAsB;IACxD,MAAM,CAACC,UAAUC,YAAY,GAAGC,SAAS;IACzC,MAAM,EAAEC,YAAY,EAAE,GAAGC;IAEzB,MAAMC,aAAaC,YAAY;QAC3B,MAAMC,UAAU,SAAS,CAAC,SAAS,CAACR;QACpCI,aAAa;IACjB,GAAG;QAACJ;QAAQI;KAAa;IAEzB,OAAO,WAAP,GACI,oBAAC;QAAI,WAAU;qBACX,oBAACK,MAAIA;QAAC,MAAK;QAAK,WAAU;OAAsB,iCAGhD,oBAAC;QAAI,WAAU;qBACX,oBAACA,MAAIA;QAAC,MAAK;QAAK,WAAU;OACrBR,WAAWD,SAAS,IAAI,MAAM,CAAC,oBAEpC,oBAACU,YAAUA;QACP,MAAMT,WAAW,WAAXA,GAAW,oBAACU,mCAAiBA,QAAAA,WAAAA,GAAM,oBAACC,gBAAcA;QACxD,SAAQ;QACR,MAAK;QACL,SAAS,IAAMV,YAAYW,CAAAA,OAAQ,CAACA;QACpC,cAAYZ,WAAW,gBAAgB;sBAE3C,oBAACS,YAAUA;QACP,oBAAM,oBAACI,iCAAQA;QACf,SAAQ;QACR,MAAK;QACL,SAAS,IAAM,KAAKR;QACpB,cAAW;;AAK/B"}
1
+ {"version":3,"file":"admin/presentation/WebhookForm/components/SigningSecret.js","sources":["../../../../../src/admin/presentation/WebhookForm/components/SigningSecret.tsx"],"sourcesContent":["import React, { useState, useCallback } from \"react\";\nimport { observer } from \"mobx-react-lite\";\nimport { IconButton, Text } from \"@webiny/admin-ui\";\nimport { useSnackbar } from \"@webiny/app-admin/hooks/index.js\";\nimport { ReactComponent as VisibilityIcon } from \"@webiny/icons/visibility.svg\";\nimport { ReactComponent as VisibilityOffIcon } from \"@webiny/icons/visibility_off.svg\";\nimport { ReactComponent as CopyIcon } from \"@webiny/icons/content_copy.svg\";\nimport type { IWebhookFormPresenter } from \"../abstractions.js\";\n\ninterface SigningSecretProps {\n presenter: IWebhookFormPresenter;\n}\n\nexport const SigningSecret = observer(function SigningSecret({ presenter }: SigningSecretProps) {\n const { vm } = presenter;\n const [revealed, setRevealed] = useState(false);\n const { showSnackbar } = useSnackbar();\n\n if (vm.isNew || !vm.webhook?.signingSecret) {\n return null;\n }\n\n const secret = vm.webhook.signingSecret;\n\n const handleCopy = useCallback(async () => {\n await navigator.clipboard.writeText(secret);\n showSnackbar(\"Signing secret copied to clipboard.\");\n }, [secret, showSnackbar]);\n\n return (\n <div className=\"flex flex-col gap-xs\">\n <Text size=\"sm\" className=\"text-neutral-strong\">\n Signing Secret\n </Text>\n <div className=\"flex items-center gap-sm rounded-sm border-sm border-neutral-muted px-sm py-xs\">\n <Text size=\"sm\" className=\"flex-1 font-mono select-all\">\n {revealed ? secret : \"•\".repeat(24)}\n </Text>\n <IconButton\n icon={revealed ? <VisibilityOffIcon /> : <VisibilityIcon />}\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => setRevealed(prev => !prev)}\n aria-label={revealed ? \"Hide secret\" : \"Reveal secret\"}\n />\n <IconButton\n icon={<CopyIcon />}\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => void handleCopy()}\n aria-label=\"Copy secret\"\n />\n </div>\n </div>\n );\n});\n"],"names":["SigningSecret","observer","presenter","vm","revealed","setRevealed","useState","showSnackbar","useSnackbar","secret","handleCopy","useCallback","navigator","Text","IconButton","VisibilityOffIcon","VisibilityIcon","prev","CopyIcon"],"mappings":";;;;;;;AAaO,MAAMA,8BAAgBC,SAAS,SAAuB,EAAEC,SAAS,EAAsB;IAC1F,MAAM,EAAEC,EAAE,EAAE,GAAGD;IACf,MAAM,CAACE,UAAUC,YAAY,GAAGC,SAAS;IACzC,MAAM,EAAEC,YAAY,EAAE,GAAGC;IAEzB,IAAIL,GAAG,KAAK,IAAI,CAACA,GAAG,OAAO,EAAE,eACzB,OAAO;IAGX,MAAMM,SAASN,GAAG,OAAO,CAAC,aAAa;IAEvC,MAAMO,aAAaC,YAAY;QAC3B,MAAMC,UAAU,SAAS,CAAC,SAAS,CAACH;QACpCF,aAAa;IACjB,GAAG;QAACE;QAAQF;KAAa;IAEzB,OAAO,WAAP,GACI,oBAAC;QAAI,WAAU;qBACX,oBAACM,MAAIA;QAAC,MAAK;QAAK,WAAU;OAAsB,iCAGhD,oBAAC;QAAI,WAAU;qBACX,oBAACA,MAAIA;QAAC,MAAK;QAAK,WAAU;OACrBT,WAAWK,SAAS,IAAI,MAAM,CAAC,oBAEpC,oBAACK,YAAUA;QACP,MAAMV,WAAW,WAAXA,GAAW,oBAACW,mCAAiBA,QAAAA,WAAAA,GAAM,oBAACC,gBAAcA;QACxD,SAAQ;QACR,MAAK;QACL,SAAS,IAAMX,YAAYY,CAAAA,OAAQ,CAACA;QACpC,cAAYb,WAAW,gBAAgB;sBAE3C,oBAACU,YAAUA;QACP,oBAAM,oBAACI,iCAAQA;QACf,SAAQ;QACR,MAAK;QACL,SAAS,IAAM,KAAKR;QACpB,cAAW;;AAK/B"}
@@ -1,9 +1,8 @@
1
- import react, { useEffect, useMemo } from "react";
1
+ import react, { useCallback, useEffect, useMemo } from "react";
2
2
  import { observer } from "mobx-react-lite";
3
3
  import { DiContainerProvider, useContainer, useFeature, useRoute } from "@webiny/app";
4
- import { FormErrors, useRouter } from "@webiny/app-admin";
5
- import { Button, Heading, OverlayLoader, Separator } from "@webiny/admin-ui";
6
- import { FormView } from "@webiny/app-admin/features/formModel/FormView.js";
4
+ import { FormErrors, FormView, SimpleForm, SimpleFormContent, SimpleFormFooter, SimpleFormHeader, useFieldRenderers, useRouter } from "@webiny/app-admin";
5
+ import { Button, OverlayLoader, useToast } from "@webiny/admin-ui";
7
6
  import { WebhookFormPresenterFeature } from "../feature.js";
8
7
  import { GetWebhookFeature } from "../../../features/getWebhook/feature.js";
9
8
  import { CreateWebhookFeature } from "../../../features/createWebhook/feature.js";
@@ -13,52 +12,67 @@ import { ListAvailableEventsFeature } from "../../../features/listAvailableEvent
13
12
  import { WebhookPermissionsFeature } from "../../../features/permissions/feature.js";
14
13
  import { Routes } from "../../../routes.js";
15
14
  import { SigningSecret } from "./SigningSecret.js";
16
- import { WebhookDeliveriesDrawer } from "../../WebhookDeliveries/components/WebhookDeliveriesDrawer.js";
15
+ import { HasPermission } from "../../security/HasPermission.js";
16
+ const SectionHeading = ({ field })=>/*#__PURE__*/ react.createElement("span", {
17
+ className: "text-md font-semibold"
18
+ }, String(field.label ?? ""));
17
19
  const WebhookFormView_WebhookFormViewInner = observer(function() {
18
20
  const { presenter } = useFeature(WebhookFormPresenterFeature);
19
21
  const { goToRoute } = useRouter();
20
22
  const { route } = useRoute(Routes.Form);
23
+ const toast = useToast();
21
24
  const id = route.params.id;
25
+ const defaultRenderers = useFieldRenderers();
26
+ const renderers = useMemo(()=>({
27
+ ...defaultRenderers,
28
+ "element:sectionHeading": SectionHeading
29
+ }), [
30
+ defaultRenderers
31
+ ]);
22
32
  useEffect(()=>{
23
33
  presenter.init(id);
24
34
  }, [
25
35
  presenter,
26
36
  id
27
37
  ]);
28
- const { vm, actions } = presenter;
29
- if (vm.loading) return /*#__PURE__*/ react.createElement(OverlayLoader, null);
30
- return /*#__PURE__*/ react.createElement(react.Fragment, null, /*#__PURE__*/ react.createElement("div", {
31
- className: "flex flex-col h-main-content"
32
- }, /*#__PURE__*/ react.createElement("div", {
33
- className: "flex items-center justify-between py-sm px-md"
34
- }, /*#__PURE__*/ react.createElement(Heading, {
35
- level: 5
36
- }, vm.isNew ? "Create Webhook" : vm.webhook?.name ?? "Edit Webhook"), /*#__PURE__*/ react.createElement("div", {
37
- className: "flex gap-sm"
38
- }, !vm.isNew && /*#__PURE__*/ react.createElement(Button, {
39
- variant: "secondary",
40
- onClick: ()=>actions.openDeliveries()
41
- }, "Deliveries"), /*#__PURE__*/ react.createElement(Button, {
38
+ const saveForm = useCallback(async ()=>{
39
+ const res = await presenter.save();
40
+ if (res) toast.showSuccessToast({
41
+ title: "Webhook saved successfully!"
42
+ });
43
+ }, [
44
+ presenter
45
+ ]);
46
+ const { vm } = presenter;
47
+ return /*#__PURE__*/ react.createElement(SimpleForm, null, vm.loading ? /*#__PURE__*/ react.createElement(OverlayLoader, {
48
+ text: "Loading..."
49
+ }) : null, vm.saving ? /*#__PURE__*/ react.createElement(OverlayLoader, {
50
+ text: "Saving..."
51
+ }) : null, vm.form.errors.length > 0 ? /*#__PURE__*/ react.createElement("div", {
52
+ className: "mb-lg"
53
+ }, /*#__PURE__*/ react.createElement(FormErrors, {
54
+ form: vm.form
55
+ })) : null, /*#__PURE__*/ react.createElement(SimpleFormHeader, {
56
+ title: vm.isNew ? "Create Webhook" : vm.webhook?.name ?? "Edit Webhook"
57
+ }), /*#__PURE__*/ react.createElement(SimpleFormContent, null, /*#__PURE__*/ react.createElement(FormView, {
58
+ name: "Webhook",
59
+ form: vm.form,
60
+ renderers: renderers
61
+ }), /*#__PURE__*/ react.createElement(SigningSecret, {
62
+ presenter: presenter
63
+ })), /*#__PURE__*/ react.createElement(SimpleFormFooter, {
64
+ className: "border-t-sm border-t-neutral-dimmed pt-lg"
65
+ }, /*#__PURE__*/ react.createElement(Button, {
42
66
  variant: "secondary",
43
67
  onClick: ()=>goToRoute(Routes.List)
44
- }, "Cancel"), vm.permissions.canEdit && /*#__PURE__*/ react.createElement(Button, {
68
+ }, "Cancel"), /*#__PURE__*/ react.createElement(HasPermission, {
69
+ entity: "webhook",
70
+ action: "edit"
71
+ }, /*#__PURE__*/ react.createElement(Button, {
45
72
  variant: "primary",
46
- onClick: ()=>void actions.save(),
73
+ onClick: saveForm,
47
74
  disabled: vm.saving
48
- }, vm.saving ? "Saving..." : "Save"))), /*#__PURE__*/ react.createElement(Separator, null), /*#__PURE__*/ react.createElement("div", {
49
- className: "p-lg"
50
- }, /*#__PURE__*/ react.createElement(react.Fragment, null, /*#__PURE__*/ react.createElement(FormErrors, {
51
- form: vm.form
52
- }), /*#__PURE__*/ react.createElement(FormView, {
53
- name: "Webhook",
54
- form: vm.form
55
- }), !vm.isNew && vm.webhook?.signingSecret && /*#__PURE__*/ react.createElement(SigningSecret, {
56
- secret: vm.webhook.signingSecret
57
- })))), vm.showDeliveries && vm.webhook && /*#__PURE__*/ react.createElement(WebhookDeliveriesDrawer, {
58
- webhookId: vm.webhook.id,
59
- open: vm.showDeliveries,
60
- onClose: ()=>actions.closeDeliveries()
61
- }));
75
+ }, vm.saving ? "Saving..." : "Save"))));
62
76
  });
63
77
  const WebhookFormView = ()=>{
64
78
  const container = useContainer();