@nocobase/plugin-notification-manager 2.1.0-beta.8 → 2.1.0

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/client-v2.d.ts +2 -0
  2. package/client-v2.js +1 -0
  3. package/dist/client/507.6b177256a5fdfe2f.js +10 -0
  4. package/dist/client/89.4f9da72110fbe97a.js +10 -0
  5. package/dist/client/index.js +1 -1
  6. package/dist/client-v2/49.83c515a7f909c364.js +10 -0
  7. package/dist/client-v2/852.543c355801fd322f.js +10 -0
  8. package/dist/client-v2/components/ContentConfigForm.d.ts +14 -0
  9. package/dist/client-v2/components/MessageConfigForm.d.ts +12 -0
  10. package/dist/client-v2/components/User/UserAddition.d.ts +16 -0
  11. package/dist/client-v2/components/User/UserSelect.d.ts +16 -0
  12. package/dist/client-v2/components/User/index.d.ts +12 -0
  13. package/dist/client-v2/index.d.ts +15 -0
  14. package/dist/client-v2/index.js +10 -0
  15. package/dist/client-v2/locale.d.ts +12 -0
  16. package/dist/client-v2/notification-manager.d.ts +36 -0
  17. package/dist/client-v2/pages/ChannelsPage.d.ts +10 -0
  18. package/dist/client-v2/pages/LogsPage.d.ts +10 -0
  19. package/dist/client-v2/plugin.d.ts +19 -0
  20. package/dist/client-v2/utils/notificationTypeOptions.d.ts +34 -0
  21. package/dist/collections/channel.d.ts +1 -0
  22. package/dist/collections/channel.js +1 -0
  23. package/dist/collections/messageLog.d.ts +1 -0
  24. package/dist/collections/messageLog.js +1 -0
  25. package/dist/externalVersion.js +14 -9
  26. package/dist/locale/de-DE.json +1 -0
  27. package/dist/locale/en-US.json +1 -0
  28. package/dist/locale/es-ES.json +1 -0
  29. package/dist/locale/fr-FR.json +1 -0
  30. package/dist/locale/hu-HU.json +1 -0
  31. package/dist/locale/id-ID.json +1 -0
  32. package/dist/locale/it-IT.json +1 -0
  33. package/dist/locale/ja-JP.json +1 -0
  34. package/dist/locale/ko-KR.json +1 -0
  35. package/dist/locale/nl-NL.json +1 -0
  36. package/dist/locale/pt-BR.json +1 -0
  37. package/dist/locale/ru-RU.json +1 -0
  38. package/dist/locale/tr-TR.json +1 -0
  39. package/dist/locale/uk-UA.json +1 -0
  40. package/dist/locale/vi-VN.json +1 -0
  41. package/dist/locale/zh-CN.json +1 -0
  42. package/dist/locale/zh-TW.json +1 -0
  43. package/dist/node_modules/uuid/dist/bin/uuid +2 -0
  44. package/dist/node_modules/uuid/dist/commonjs-browser/index.js +104 -0
  45. package/dist/node_modules/uuid/dist/commonjs-browser/max.js +7 -0
  46. package/dist/node_modules/uuid/dist/commonjs-browser/md5.js +200 -0
  47. package/dist/node_modules/uuid/dist/commonjs-browser/native.js +10 -0
  48. package/dist/node_modules/uuid/dist/commonjs-browser/nil.js +7 -0
  49. package/dist/node_modules/uuid/dist/commonjs-browser/parse.js +44 -0
  50. package/dist/node_modules/uuid/dist/commonjs-browser/regex.js +7 -0
  51. package/dist/node_modules/uuid/dist/commonjs-browser/rng.js +23 -0
  52. package/dist/node_modules/uuid/dist/commonjs-browser/sha1.js +82 -0
  53. package/dist/node_modules/uuid/dist/commonjs-browser/stringify.js +38 -0
  54. package/dist/node_modules/uuid/dist/commonjs-browser/v1.js +131 -0
  55. package/dist/node_modules/uuid/dist/commonjs-browser/v1ToV6.js +26 -0
  56. package/dist/node_modules/uuid/dist/commonjs-browser/v3.js +11 -0
  57. package/dist/node_modules/uuid/dist/commonjs-browser/v35.js +63 -0
  58. package/dist/node_modules/uuid/dist/commonjs-browser/v4.js +32 -0
  59. package/dist/node_modules/uuid/dist/commonjs-browser/v5.js +11 -0
  60. package/dist/node_modules/uuid/dist/commonjs-browser/v6.js +42 -0
  61. package/dist/node_modules/uuid/dist/commonjs-browser/v6ToV1.js +26 -0
  62. package/dist/node_modules/uuid/dist/commonjs-browser/v7.js +152 -0
  63. package/dist/node_modules/uuid/dist/commonjs-browser/validate.js +12 -0
  64. package/dist/node_modules/uuid/dist/commonjs-browser/version.js +15 -0
  65. package/dist/node_modules/uuid/dist/esm-browser/index.js +14 -0
  66. package/dist/node_modules/uuid/dist/esm-browser/max.js +1 -0
  67. package/dist/node_modules/uuid/dist/esm-browser/md5.js +194 -0
  68. package/dist/node_modules/uuid/dist/esm-browser/native.js +4 -0
  69. package/dist/node_modules/uuid/dist/esm-browser/nil.js +1 -0
  70. package/dist/node_modules/uuid/dist/esm-browser/parse.js +37 -0
  71. package/dist/node_modules/uuid/dist/esm-browser/regex.js +1 -0
  72. package/dist/node_modules/uuid/dist/esm-browser/rng.js +17 -0
  73. package/dist/node_modules/uuid/dist/esm-browser/sha1.js +76 -0
  74. package/dist/node_modules/uuid/dist/esm-browser/stringify.js +31 -0
  75. package/dist/node_modules/uuid/dist/esm-browser/v1.js +125 -0
  76. package/dist/node_modules/uuid/dist/esm-browser/v1ToV6.js +20 -0
  77. package/dist/node_modules/uuid/dist/esm-browser/v3.js +4 -0
  78. package/dist/node_modules/uuid/dist/esm-browser/v35.js +55 -0
  79. package/dist/node_modules/uuid/dist/esm-browser/v4.js +25 -0
  80. package/dist/node_modules/uuid/dist/esm-browser/v5.js +4 -0
  81. package/dist/node_modules/uuid/dist/esm-browser/v6.js +36 -0
  82. package/dist/node_modules/uuid/dist/esm-browser/v6ToV1.js +20 -0
  83. package/dist/node_modules/uuid/dist/esm-browser/v7.js +146 -0
  84. package/dist/node_modules/uuid/dist/esm-browser/validate.js +5 -0
  85. package/dist/node_modules/uuid/dist/esm-browser/version.js +8 -0
  86. package/dist/node_modules/uuid/dist/esm-node/index.js +14 -0
  87. package/dist/node_modules/uuid/dist/esm-node/max.js +1 -0
  88. package/dist/node_modules/uuid/dist/esm-node/md5.js +10 -0
  89. package/dist/node_modules/uuid/dist/esm-node/native.js +4 -0
  90. package/dist/node_modules/uuid/dist/esm-node/nil.js +1 -0
  91. package/dist/node_modules/uuid/dist/esm-node/parse.js +37 -0
  92. package/dist/node_modules/uuid/dist/esm-node/regex.js +1 -0
  93. package/dist/node_modules/uuid/dist/esm-node/rng.js +10 -0
  94. package/dist/node_modules/uuid/dist/esm-node/sha1.js +10 -0
  95. package/dist/node_modules/uuid/dist/esm-node/stringify.js +31 -0
  96. package/dist/node_modules/uuid/dist/esm-node/v1.js +125 -0
  97. package/dist/node_modules/uuid/dist/esm-node/v1ToV6.js +20 -0
  98. package/dist/node_modules/uuid/dist/esm-node/v3.js +4 -0
  99. package/dist/node_modules/uuid/dist/esm-node/v35.js +55 -0
  100. package/dist/node_modules/uuid/dist/esm-node/v4.js +25 -0
  101. package/dist/node_modules/uuid/dist/esm-node/v5.js +4 -0
  102. package/dist/node_modules/uuid/dist/esm-node/v6.js +32 -0
  103. package/dist/node_modules/uuid/dist/esm-node/v6ToV1.js +20 -0
  104. package/dist/node_modules/uuid/dist/esm-node/v7.js +146 -0
  105. package/dist/node_modules/uuid/dist/esm-node/validate.js +5 -0
  106. package/dist/node_modules/uuid/dist/esm-node/version.js +8 -0
  107. package/dist/node_modules/uuid/dist/index.js +1 -0
  108. package/dist/node_modules/uuid/dist/max.js +7 -0
  109. package/dist/node_modules/uuid/dist/md5-browser.js +200 -0
  110. package/dist/node_modules/uuid/dist/md5.js +17 -0
  111. package/dist/node_modules/uuid/dist/native-browser.js +10 -0
  112. package/dist/node_modules/uuid/dist/native.js +11 -0
  113. package/dist/node_modules/uuid/dist/nil.js +7 -0
  114. package/dist/node_modules/uuid/dist/parse.js +44 -0
  115. package/dist/node_modules/uuid/dist/regex.js +7 -0
  116. package/dist/node_modules/uuid/dist/rng-browser.js +23 -0
  117. package/dist/node_modules/uuid/dist/rng.js +17 -0
  118. package/dist/node_modules/uuid/dist/sha1-browser.js +82 -0
  119. package/dist/node_modules/uuid/dist/sha1.js +17 -0
  120. package/dist/node_modules/uuid/dist/stringify.js +38 -0
  121. package/dist/node_modules/uuid/dist/uuid-bin.js +75 -0
  122. package/dist/node_modules/uuid/dist/v1.js +131 -0
  123. package/dist/node_modules/uuid/dist/v1ToV6.js +26 -0
  124. package/dist/node_modules/uuid/dist/v3.js +11 -0
  125. package/dist/node_modules/uuid/dist/v35.js +63 -0
  126. package/dist/node_modules/uuid/dist/v4.js +32 -0
  127. package/dist/node_modules/uuid/dist/v5.js +11 -0
  128. package/dist/node_modules/uuid/dist/v6.js +38 -0
  129. package/dist/node_modules/uuid/dist/v6ToV1.js +26 -0
  130. package/dist/node_modules/uuid/dist/v7.js +152 -0
  131. package/dist/node_modules/uuid/dist/validate.js +12 -0
  132. package/dist/node_modules/uuid/dist/version.js +15 -0
  133. package/dist/node_modules/uuid/package.json +1 -0
  134. package/dist/server/base-notification-channel.d.ts +3 -1
  135. package/dist/server/manager.d.ts +52 -5
  136. package/dist/server/manager.js +168 -17
  137. package/dist/server/plugin.d.ts +49 -2
  138. package/dist/server/plugin.js +65 -2
  139. package/dist/server/types.d.ts +7 -3
  140. package/package.json +3 -2
  141. package/dist/client/035b24990a46d186.js +0 -10
  142. package/dist/client/b1941306dc0db9f3.js +0 -10
@@ -8,19 +8,66 @@
8
8
  */
9
9
  import { Registry } from '@nocobase/utils';
10
10
  import PluginNotificationManagerServer from './plugin';
11
- import type { NotificationChannelConstructor, RegisterServerTypeFnParams, SendOptions, SendUserOptions, WriteLogOptions } from './types';
11
+ import type { NotificationQueueMessage, NotificationChannelConstructor, RegisterServerTypeFnParams, ReceiversOptions, SendOptions, SendUserOptions, WriteLogOptions } from './types';
12
12
  export declare class NotificationManager implements NotificationManager {
13
+ private static readonly SLOW_SEND_THRESHOLD_MS;
13
14
  private plugin;
14
15
  channelTypes: Registry<{
15
16
  Channel: NotificationChannelConstructor;
17
+ useQueue: boolean;
16
18
  }>;
17
19
  constructor({ plugin }: {
18
20
  plugin: PluginNotificationManagerServer;
19
21
  });
20
- registerType({ type, Channel }: RegisterServerTypeFnParams): void;
21
- createSendingRecord: (options: WriteLogOptions) => Promise<any>;
22
+ registerType({ type, Channel, useQueue }: RegisterServerTypeFnParams): void;
23
+ createSendingRecord: (options: WriteLogOptions) => Promise<import("@nocobase/database").Model<any, any>>;
24
+ private toQueueMessage;
25
+ private getQueuedResult;
26
+ private getDirectResult;
27
+ private getDeferredResult;
28
+ private shouldUseQueue;
29
+ private enqueue;
30
+ private dispatchAfterCommit;
22
31
  findChannel(name: string): Promise<any>;
23
- send(params: SendOptions): Promise<any>;
24
- sendToUsers(options: SendUserOptions): Promise<any[]>;
32
+ private getReceiverMeta;
33
+ send(params: SendOptions): Promise<{
34
+ status: "success" | "failure";
35
+ reason: string;
36
+ triggerFrom: string;
37
+ channelName: string;
38
+ receivers: ReceiversOptions;
39
+ queued: boolean;
40
+ } | {
41
+ status: "success";
42
+ triggerFrom: string;
43
+ channelName: string;
44
+ receivers: ReceiversOptions;
45
+ } | {
46
+ status: "failure";
47
+ reason: string;
48
+ triggerFrom: string;
49
+ channelName: string;
50
+ receivers: ReceiversOptions;
51
+ }>;
52
+ sendNow(params: NotificationQueueMessage): Promise<any>;
53
+ sendToUsers(options: SendUserOptions): Promise<({
54
+ status: "success" | "failure";
55
+ reason: string;
56
+ triggerFrom: string;
57
+ channelName: string;
58
+ receivers: ReceiversOptions;
59
+ queued: boolean;
60
+ } | {
61
+ status: "success";
62
+ triggerFrom: string;
63
+ channelName: string;
64
+ receivers: ReceiversOptions;
65
+ } | {
66
+ status: "failure";
67
+ reason: string;
68
+ triggerFrom: string;
69
+ channelName: string;
70
+ receivers: ReceiversOptions;
71
+ })[]>;
25
72
  }
26
73
  export default NotificationManager;
@@ -31,65 +31,215 @@ __export(manager_exports, {
31
31
  });
32
32
  module.exports = __toCommonJS(manager_exports);
33
33
  var import_utils = require("@nocobase/utils");
34
+ var import_uuid = require("uuid");
34
35
  var import_constant = require("../constant");
35
36
  var import_compile = require("./utils/compile");
36
37
  class NotificationManager {
38
+ static SLOW_SEND_THRESHOLD_MS = 500;
37
39
  plugin;
38
40
  channelTypes = new import_utils.Registry();
39
41
  constructor({ plugin }) {
40
42
  this.plugin = plugin;
41
43
  }
42
- registerType({ type, Channel }) {
43
- this.channelTypes.register(type, { Channel });
44
+ registerType({ type, Channel, useQueue = true }) {
45
+ this.channelTypes.register(type, { Channel, useQueue });
44
46
  }
45
47
  createSendingRecord = async (options) => {
46
- const logsRepo = this.plugin.app.db.getRepository(import_constant.COLLECTION_NAME.logs);
47
- return logsRepo.create({ values: options });
48
+ const LogsModel = this.plugin.app.db.getModel(import_constant.COLLECTION_NAME.logs);
49
+ return LogsModel.create(
50
+ {
51
+ id: (0, import_uuid.v4)(),
52
+ ...options
53
+ },
54
+ {
55
+ hooks: false,
56
+ validate: false
57
+ }
58
+ );
48
59
  };
60
+ toQueueMessage(params) {
61
+ const { transaction, ...message } = params;
62
+ return message;
63
+ }
64
+ getQueuedResult(params) {
65
+ return {
66
+ status: "success",
67
+ triggerFrom: params.triggerFrom,
68
+ channelName: params.channelName,
69
+ receivers: params.receivers,
70
+ queued: true
71
+ };
72
+ }
73
+ getDirectResult(params, result) {
74
+ return {
75
+ status: result.status,
76
+ reason: result.reason,
77
+ triggerFrom: params.triggerFrom,
78
+ channelName: params.channelName,
79
+ receivers: params.receivers,
80
+ queued: false
81
+ };
82
+ }
83
+ getDeferredResult(params) {
84
+ return {
85
+ status: "success",
86
+ triggerFrom: params.triggerFrom,
87
+ channelName: params.channelName,
88
+ receivers: params.receivers
89
+ };
90
+ }
91
+ async shouldUseQueue(channelName) {
92
+ const channel = await this.findChannel(channelName);
93
+ if (!channel) {
94
+ return true;
95
+ }
96
+ const channelType = this.channelTypes.get(channel.notificationType);
97
+ return (channelType == null ? void 0 : channelType.useQueue) ?? true;
98
+ }
99
+ async enqueue(message) {
100
+ await this.plugin.app.eventQueue.publish(this.plugin.sendQueueChannel, message);
101
+ }
102
+ async dispatchAfterCommit(message) {
103
+ const useQueue = await this.shouldUseQueue(message.channelName);
104
+ if (useQueue) {
105
+ await this.enqueue(message);
106
+ return;
107
+ }
108
+ await this.sendNow(message);
109
+ }
49
110
  async findChannel(name) {
50
- const repository = this.plugin.app.db.getRepository(import_constant.COLLECTION_NAME.channels);
51
- const instance = await repository.findOne({ filterByTk: name });
52
- if (!instance) {
53
- return null;
111
+ return await this.plugin.getChannel(name);
112
+ }
113
+ getReceiverMeta(receivers) {
114
+ if (!receivers) {
115
+ return {};
116
+ }
117
+ if (receivers.type === "userId") {
118
+ return {
119
+ receiverType: receivers.type,
120
+ receiverCount: receivers.value.length
121
+ };
54
122
  }
55
- return this.plugin.app.environment.renderJsonTemplate(instance.toJSON());
123
+ return {
124
+ receiverType: receivers.type
125
+ };
56
126
  }
57
127
  async send(params) {
58
- this.plugin.logger.info("receive sending message request", params);
128
+ const queueMessage = this.toQueueMessage(params);
129
+ const transaction = params.transaction;
130
+ if (transaction == null ? void 0 : transaction.afterCommit) {
131
+ transaction.afterCommit(() => {
132
+ return this.dispatchAfterCommit(queueMessage).catch((error) => {
133
+ this.plugin.logger.error("notification dispatch failed after transaction committed", {
134
+ channelName: params.channelName,
135
+ triggerFrom: params.triggerFrom,
136
+ reason: error instanceof Error ? `${error.name}: ${error.message}` : JSON.stringify(error)
137
+ });
138
+ });
139
+ });
140
+ return this.getDeferredResult(params);
141
+ }
142
+ const useQueue = await this.shouldUseQueue(params.channelName);
143
+ if (!useQueue) {
144
+ const result = await this.sendNow(queueMessage);
145
+ return this.getDirectResult(params, result);
146
+ }
147
+ try {
148
+ await this.enqueue(queueMessage);
149
+ return this.getQueuedResult(params);
150
+ } catch (error) {
151
+ const reason = error instanceof Error ? `${error.name}: ${error.message}` : JSON.stringify(error);
152
+ this.plugin.logger.error("notification queue publish failed", {
153
+ channelName: params.channelName,
154
+ triggerFrom: params.triggerFrom,
155
+ reason
156
+ });
157
+ return {
158
+ status: "failure",
159
+ reason,
160
+ triggerFrom: params.triggerFrom,
161
+ channelName: params.channelName,
162
+ receivers: params.receivers
163
+ };
164
+ }
165
+ }
166
+ async sendNow(params) {
167
+ const startedAt = Date.now();
168
+ const receiverMeta = this.getReceiverMeta(params.receivers);
169
+ const compileStartedAt = Date.now();
59
170
  const message = (0, import_compile.compile)(params.message ?? {}, params.data ?? {});
171
+ const compileMs = Date.now() - compileStartedAt;
60
172
  const messageData = { ...params.receivers ? { receivers: params.receivers } : {}, ...message };
61
173
  const logData = {
62
174
  triggerFrom: params.triggerFrom,
63
175
  channelName: params.channelName,
64
176
  message: messageData
65
177
  };
178
+ let findChannelMs = 0;
179
+ let channelSendMs = 0;
66
180
  try {
181
+ const findChannelStartedAt = Date.now();
67
182
  const channel = await this.findChannel(params.channelName);
183
+ findChannelMs = Date.now() - findChannelStartedAt;
68
184
  if (channel) {
69
185
  const Channel = this.channelTypes.get(channel.notificationType).Channel;
70
186
  const instance = new Channel(this.plugin.app);
71
187
  logData.channelTitle = channel.title;
72
188
  logData.notificationType = channel.notificationType;
73
189
  logData.receivers = params.receivers;
74
- const result = await instance.send({ message, channel, receivers: params.receivers });
190
+ const channelSendStartedAt = Date.now();
191
+ const result = await instance.send({
192
+ message,
193
+ channel,
194
+ receivers: params.receivers
195
+ });
196
+ channelSendMs = Date.now() - channelSendStartedAt;
75
197
  logData.status = result.status;
76
198
  logData.reason = result.reason;
77
199
  } else {
78
200
  logData.status = "failure";
79
201
  logData.reason = "channel not found";
80
202
  }
81
- this.createSendingRecord(logData);
203
+ await this.createSendingRecord(logData);
204
+ const totalMs = Date.now() - startedAt;
205
+ if (totalMs >= NotificationManager.SLOW_SEND_THRESHOLD_MS) {
206
+ this.plugin.logger.warn("notification send is slow", {
207
+ channelName: params.channelName,
208
+ triggerFrom: params.triggerFrom,
209
+ status: logData.status,
210
+ notificationType: logData.notificationType,
211
+ compileMs,
212
+ findChannelMs,
213
+ channelSendMs,
214
+ totalMs,
215
+ ...receiverMeta
216
+ });
217
+ }
82
218
  return logData;
83
219
  } catch (error) {
84
220
  logData.status = "failure";
85
- this.plugin.logger.error(`notification send failed, options: ${JSON.stringify(error)}`);
86
- logData.reason = JSON.stringify(error);
87
- this.createSendingRecord(logData);
221
+ const totalMs = Date.now() - startedAt;
222
+ const reason = error instanceof Error ? `${error.name}: ${error.message}` : JSON.stringify(error);
223
+ this.plugin.logger.error("notification send failed", {
224
+ channelName: params.channelName,
225
+ triggerFrom: params.triggerFrom,
226
+ compileMs,
227
+ findChannelMs,
228
+ channelSendMs,
229
+ totalMs,
230
+ reason,
231
+ ...receiverMeta
232
+ });
233
+ logData.reason = reason;
234
+ await this.createSendingRecord(logData);
88
235
  return logData;
89
236
  }
90
237
  }
91
238
  async sendToUsers(options) {
92
- this.plugin.logger.info(`notificationManager.sendToUsers options: ${JSON.stringify(options)}`);
239
+ this.plugin.logger.debug("notificationManager.sendToUsers", {
240
+ channelCount: options.channels.length,
241
+ userCount: options.userIds.length
242
+ });
93
243
  const { userIds, channels, message, data = {} } = options;
94
244
  return await Promise.all(
95
245
  channels.map(
@@ -98,7 +248,8 @@ class NotificationManager {
98
248
  message,
99
249
  data,
100
250
  triggerFrom: "sendToUsers",
101
- receivers: { value: userIds, type: "userId" }
251
+ receivers: { value: userIds, type: "userId" },
252
+ transaction: options.transaction
102
253
  })
103
254
  )
104
255
  );
@@ -6,18 +6,65 @@
6
6
  * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
+ import type { Cache } from '@nocobase/cache';
9
10
  import type { Logger } from '@nocobase/logger';
11
+ import { Transactionable } from '@nocobase/database';
10
12
  import { Plugin } from '@nocobase/server';
11
13
  import { RegisterServerTypeFnParams, SendOptions, SendUserOptions } from './types';
12
14
  export declare class PluginNotificationManagerServer extends Plugin {
15
+ private static readonly CHANNELS_CACHE_KEY;
13
16
  private manager;
14
17
  logger: Logger;
18
+ cache: Cache;
19
+ get sendQueueChannel(): string;
20
+ private ensureCache;
21
+ parseChannel(instance: any): any;
22
+ loadChannels(options?: Transactionable): Promise<void>;
23
+ getChannel(name: string): Promise<any>;
15
24
  get channelTypes(): import("@nocobase/utils").Registry<{
16
25
  Channel: import("./types").NotificationChannelConstructor;
26
+ useQueue: boolean;
17
27
  }>;
18
28
  registerChannelType(params: RegisterServerTypeFnParams): void;
19
- send(options: SendOptions): Promise<any>;
20
- sendToUsers(options: SendUserOptions): Promise<any[]>;
29
+ send(options: SendOptions): Promise<{
30
+ status: "success" | "failure";
31
+ reason: string;
32
+ triggerFrom: string;
33
+ channelName: string;
34
+ receivers: import("./types").ReceiversOptions;
35
+ queued: boolean;
36
+ } | {
37
+ status: "success";
38
+ triggerFrom: string;
39
+ channelName: string;
40
+ receivers: import("./types").ReceiversOptions;
41
+ } | {
42
+ status: "failure";
43
+ reason: string;
44
+ triggerFrom: string;
45
+ channelName: string;
46
+ receivers: import("./types").ReceiversOptions;
47
+ }>;
48
+ sendNow(options: SendOptions): Promise<any>;
49
+ sendToUsers(options: SendUserOptions): Promise<({
50
+ status: "success" | "failure";
51
+ reason: string;
52
+ triggerFrom: string;
53
+ channelName: string;
54
+ receivers: import("./types").ReceiversOptions;
55
+ queued: boolean;
56
+ } | {
57
+ status: "success";
58
+ triggerFrom: string;
59
+ channelName: string;
60
+ receivers: import("./types").ReceiversOptions;
61
+ } | {
62
+ status: "failure";
63
+ reason: string;
64
+ triggerFrom: string;
65
+ channelName: string;
66
+ receivers: import("./types").ReceiversOptions;
67
+ })[]>;
21
68
  afterAdd(): Promise<void>;
22
69
  beforeLoad(): Promise<void>;
23
70
  load(): Promise<void>;
@@ -41,10 +41,50 @@ __export(plugin_exports, {
41
41
  });
42
42
  module.exports = __toCommonJS(plugin_exports);
43
43
  var import_server = require("@nocobase/server");
44
+ var import_constant = require("../constant");
44
45
  var import_manager = __toESM(require("./manager"));
45
46
  class PluginNotificationManagerServer extends import_server.Plugin {
47
+ static CHANNELS_CACHE_KEY = "channels";
46
48
  manager;
47
49
  logger;
50
+ cache;
51
+ get sendQueueChannel() {
52
+ return `${this.name}.send`;
53
+ }
54
+ async ensureCache() {
55
+ if (!this.cache) {
56
+ this.cache = await this.app.cacheManager.createCache({
57
+ name: this.name,
58
+ prefix: this.name
59
+ });
60
+ }
61
+ return this.cache;
62
+ }
63
+ parseChannel(instance) {
64
+ return this.app.environment.renderJsonTemplate(instance.toJSON());
65
+ }
66
+ async loadChannels(options) {
67
+ const cache = await this.ensureCache();
68
+ const repository = this.app.db.getRepository(import_constant.COLLECTION_NAME.channels);
69
+ const channels = await repository.find({
70
+ transaction: options == null ? void 0 : options.transaction
71
+ });
72
+ const channelsCache = {};
73
+ for (const channel of channels) {
74
+ channelsCache[channel.get("name")] = this.parseChannel(channel);
75
+ }
76
+ await cache.set(PluginNotificationManagerServer.CHANNELS_CACHE_KEY, channelsCache);
77
+ }
78
+ async getChannel(name) {
79
+ const cache = await this.ensureCache();
80
+ const channels = await cache.get(PluginNotificationManagerServer.CHANNELS_CACHE_KEY) || void 0;
81
+ if (!channels) {
82
+ await this.loadChannels();
83
+ const reloadedChannels = await cache.get(PluginNotificationManagerServer.CHANNELS_CACHE_KEY);
84
+ return (reloadedChannels == null ? void 0 : reloadedChannels[name]) || null;
85
+ }
86
+ return channels[name] || null;
87
+ }
48
88
  get channelTypes() {
49
89
  return this.manager.channelTypes;
50
90
  }
@@ -54,6 +94,10 @@ class PluginNotificationManagerServer extends import_server.Plugin {
54
94
  async send(options) {
55
95
  return await this.manager.send(options);
56
96
  }
97
+ async sendNow(options) {
98
+ const { transaction, ...message } = options;
99
+ return await this.manager.sendNow(message);
100
+ }
57
101
  async sendToUsers(options) {
58
102
  return await this.manager.sendToUsers(options);
59
103
  }
@@ -69,8 +113,8 @@ class PluginNotificationManagerServer extends import_server.Plugin {
69
113
  this.app.resourceManager.registerActionHandler("messages:send", async (ctx, next) => {
70
114
  var _a, _b;
71
115
  const sendOptions = (_b = (_a = ctx.action) == null ? void 0 : _a.params) == null ? void 0 : _b.values;
72
- this.manager.send(sendOptions);
73
- next();
116
+ await this.manager.send(sendOptions);
117
+ await next();
74
118
  });
75
119
  this.app.acl.registerSnippet({
76
120
  name: "pm.notification.channels",
@@ -80,16 +124,35 @@ class PluginNotificationManagerServer extends import_server.Plugin {
80
124
  name: "pm.notification.logs",
81
125
  actions: ["notificationSendLogs:*"]
82
126
  });
127
+ this.app.on("afterStart", async () => {
128
+ await this.loadChannels();
129
+ });
83
130
  }
84
131
  async load() {
132
+ const Channel = this.app.db.getModel(import_constant.COLLECTION_NAME.channels);
133
+ Channel.afterSave(async (_model, { transaction }) => {
134
+ await this.loadChannels({ transaction });
135
+ });
136
+ Channel.afterDestroy(async (_model, { transaction }) => {
137
+ await this.loadChannels({ transaction });
138
+ });
139
+ this.app.eventQueue.subscribe(this.sendQueueChannel, {
140
+ concurrency: 1,
141
+ idle: () => true,
142
+ process: async (message) => {
143
+ await this.manager.sendNow(message);
144
+ }
145
+ });
85
146
  }
86
147
  async install() {
87
148
  }
88
149
  async afterEnable() {
89
150
  }
90
151
  async afterDisable() {
152
+ this.app.eventQueue.unsubscribe(this.sendQueueChannel);
91
153
  }
92
154
  async remove() {
155
+ this.app.eventQueue.unsubscribe(this.sendQueueChannel);
93
156
  }
94
157
  }
95
158
  var plugin_default = PluginNotificationManagerServer;
@@ -6,6 +6,7 @@
6
6
  * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
+ import { Transactionable } from '@nocobase/database';
9
10
  import { Application } from '@nocobase/server';
10
11
  import { BaseNotificationChannel } from './base-notification-channel';
11
12
  /**
@@ -33,9 +34,10 @@ export type SendFnType<Message> = (args: {
33
34
  message: Message;
34
35
  channel: ChannelOptions;
35
36
  receivers?: ReceiversOptions;
37
+ transaction?: Transactionable['transaction'];
36
38
  }) => Promise<{
37
39
  message: Message;
38
- status: 'success' | 'fail';
40
+ status: 'success' | 'failure';
39
41
  reason?: string;
40
42
  }>;
41
43
  export type ReceiversOptions = {
@@ -46,14 +48,15 @@ export type ReceiversOptions = {
46
48
  type: 'channel-self-defined';
47
49
  channelType: string;
48
50
  };
49
- export interface SendOptions {
51
+ export interface SendOptions extends Transactionable {
50
52
  channelName: string;
51
53
  message: Record<string, any>;
52
54
  triggerFrom: string;
53
55
  receivers?: ReceiversOptions;
54
56
  data?: Record<string, any>;
55
57
  }
56
- export interface SendUserOptions {
58
+ export type NotificationQueueMessage = Omit<SendOptions, 'transaction'>;
59
+ export interface SendUserOptions extends Transactionable {
57
60
  userIds: number[];
58
61
  channels: string[];
59
62
  message: Record<string, any>;
@@ -63,4 +66,5 @@ export type NotificationChannelConstructor = new (app: Application) => BaseNotif
63
66
  export type RegisterServerTypeFnParams = {
64
67
  type: string;
65
68
  Channel: NotificationChannelConstructor;
69
+ useQueue?: boolean;
66
70
  };
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "description.ru-RU": "Предоставляет единый сервис управления, включающий конфигурирование каналов, логирование и другие функции, поддерживает настройку различных каналов уведомлений, включая внутренние сообщения и электронную почту.",
7
7
  "displayName.zh-CN": "通知管理",
8
8
  "description.zh-CN": "提供统一的管理服务,涵盖渠道配置、日志记录等功能,支持多种通知渠道的配置,包括站内信和电子邮件等。",
9
- "version": "2.1.0-beta.8",
9
+ "version": "2.1.0",
10
10
  "homepage": "https://docs.nocobase.com/handbook/notification-manager",
11
11
  "homepage.ru-RU": "https://docs-ru.nocobase.com/handbook/notification-manager",
12
12
  "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/notification-manager",
@@ -25,6 +25,7 @@
25
25
  "peerDependencies": {
26
26
  "@nocobase/actions": "2.x",
27
27
  "@nocobase/client": "2.x",
28
+ "@nocobase/client-v2": "2.x",
28
29
  "@nocobase/database": "2.x",
29
30
  "@nocobase/plugin-workflow": ">=0.17.0-alpha.3",
30
31
  "@nocobase/server": "2.x",
@@ -35,5 +36,5 @@
35
36
  "Notification"
36
37
  ],
37
38
  "license": "Apache-2.0",
38
- "gitHead": "5099d561c5467292414c1e77ad6bad3730d97344"
39
+ "gitHead": "9373212dd0f22cd985be1e23674d6b454944b9ee"
39
40
  }
@@ -1,10 +0,0 @@
1
- /**
2
- * This file is part of the NocoBase (R) project.
3
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
- * Authors: NocoBase Team.
5
- *
6
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
- * For more information, please refer to: https://www.nocobase.com/agreement.
8
- */
9
-
10
- "use strict";(self.webpackChunk_nocobase_plugin_notification_manager=self.webpackChunk_nocobase_plugin_notification_manager||[]).push([["969"],{358:function(e,t,o){o.r(t),o.d(t,{LogManager:function(){return f}});var n,r,i=o(772),p=o(721),a=o(156),c=o.n(a),l=o(712),s=o(807),m=o(551),d=o(655),u=o(296),y={id:{"x-component":"CollectionField","x-decorator":"FormItem","x-disabled":!0,"x-read-pretty":!0},channelName:{"x-component":"CollectionField","x-decorator":"FormItem","x-read-pretty":!0},channelTitle:{"x-component":"CollectionField","x-decorator":"FormItem","x-read-pretty":!0},notificationType:{"x-component":"CollectionField","x-decorator":"FormItem","x-read-pretty":!0},triggerFrom:{"x-component":"CollectionField","x-decorator":"FormItem","x-read-pretty":!0},status:{"x-component":"CollectionField","x-decorator":"FormItem","x-read-pretty":!0},message:{"x-component":"CollectionField","x-decorator":"FormItem","x-read-pretty":!0},reason:{"x-component":"CollectionField","x-decorator":"FormItem","x-read-pretty":!0,"x-reactions":[{dependencies:["status"],fulfill:{state:{visible:'{{$deps[0] === "failure"}}'}}}]},createdAt:{"x-component":"CollectionField","x-decorator":"FormItem","x-read-pretty":!0,"x-component-props":{dateFormat:"YYYY-MM-DD",showTime:!0,timeFormat:"HH:mm:ss"}}},x={type:"void","x-uid":"t8tkmt2b9dd",name:u.O.logs,"x-decorator":"TableBlockProvider","x-decorator-props":{collection:s.Z.name,action:"list",params:{sort:["-createdAt"]},showIndex:!0,dragSort:!1},properties:{actions:{type:"void","x-component":"ActionBar","x-component-props":{style:{marginBottom:16}},properties:{refresh:{title:"{{t('Refresh')}}","x-action":"refresh","x-component":"Action","x-use-component-props":"useRefreshActionProps","x-component-props":{icon:"ReloadOutlined"}},filter:{"x-action":"filter","x-component":"Filter.Action",title:"{{t('Filter')}}","x-use-component-props":"useFilterActionProps","x-component-props":{icon:"FilterOutlined",nonfilterable:["receiver","reason"]},"x-align":"left"}}},table:{type:"array","x-component":"TableV2","x-use-component-props":"useTableBlockProps","x-component-props":{rowKey:"id"},properties:{createdAt:{type:"void","x-component":"TableV2.Column","x-component-props":{width:100},title:'{{t("Created at")}}',properties:{createdAt:{type:"string","x-component":"CollectionField","x-pattern":"readPretty","x-component-props":{dateFormat:"YYYY-MM-DD",showTime:!0,timeFormat:"HH:mm:ss"}}}},triggerFrom:{type:"void","x-component":"TableV2.Column","x-component-props":{width:100},title:'{{t("Trigger from")}}',properties:{triggerFrom:{type:"string","x-component":"CollectionField","x-read-pretty":!0,"x-component-props":{ellipsis:!0}}}},channelTitle:{type:"void","x-component":"TableV2.Column","x-component-props":{width:100},title:'{{t("Channel display name")}}',properties:{channelTitle:{type:"string","x-component":"CollectionField","x-read-pretty":!0,"x-component-props":{ellipsis:!0}}}},notificationType:{title:'{{t("Notification type")}}',type:"void","x-component":"TableV2.Column",properties:{notificationType:{type:"string","x-component":"CollectionField","x-read-pretty":!0}}},status:{type:"void","x-component":"TableV2.Column","x-component-props":{width:100},title:'{{t("Status")}}',properties:{status:{type:"string","x-component":"CollectionField","x-pattern":"readPretty"}}},reason:{type:"void","x-component":"TableV2.Column","x-component-props":{width:200},title:'{{t("Failed reason")}}',properties:{reason:{type:"string","x-component":"CollectionField","x-read-pretty":!0,"x-component-props":{ellipsis:!0}}}},actions:{type:"void",title:'{{t("Actions")}}',"x-component":"TableV2.Column",properties:{view:{type:"void",title:'{{t("View")}}',"x-component":"Action.Link","x-component-props":{openMode:"drawer"},properties:{drawer:{type:"void",title:'{{t("Log detail")}}',"x-component":"Action.Drawer",properties:{detail:{type:"void","x-component":"FormV2","x-use-component-props":"useEditFormProps","x-decorator":"BlockItemCard",properties:(n=function(e){for(var t=1;t<arguments.length;t++){var o=null!=arguments[t]?arguments[t]:{},n=Object.keys(o);"function"==typeof Object.getOwnPropertySymbols&&(n=n.concat(Object.getOwnPropertySymbols(o).filter(function(e){return Object.getOwnPropertyDescriptor(o,e).enumerable}))),n.forEach(function(t){var n;n=o[t],t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n})}return e}({},y),r=r={footer:{type:"void","x-component":"Action.Drawer.Footer"}},Object.getOwnPropertyDescriptors?Object.defineProperties(n,Object.getOwnPropertyDescriptors(r)):(function(e,t){var o=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);o.push.apply(o,n)}return o})(Object(r)).forEach(function(e){Object.defineProperty(n,e,Object.getOwnPropertyDescriptor(r,e))}),n)}}}}}}}}}}},f=function(){var e=(0,m.oG)().t,t=(0,i.useSchemaComponentContext)(),o=(0,d.aT)(),n=(0,a.useMemo)(function(){var e,o;return e=function(e){for(var t=1;t<arguments.length;t++){var o=null!=arguments[t]?arguments[t]:{},n=Object.keys(o);"function"==typeof Object.getOwnPropertySymbols&&(n=n.concat(Object.getOwnPropertySymbols(o).filter(function(e){return Object.getOwnPropertyDescriptor(o,e).enumerable}))),n.forEach(function(t){var n;n=o[t],t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n})}return e}({},t),o=o={designable:!1},Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(o)):(function(e,t){var o=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);o.push.apply(o,n)}return o})(Object(o)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(o,t))}),e},[t]);return c().createElement(i.ExtendCollectionsProvider,{collections:[s.Z,l.Z]},c().createElement(i.SchemaComponentContext.Provider,{value:n},c().createElement(p.Card,{bordered:!1},c().createElement(i.SchemaComponent,{schema:x,scope:{t:e,useEditFormProps:d.fC,notificationTypeOptions:o}}))))};f.displayName="LogManager"},712:function(e,t,o){t.Z={name:o(296).O.channels,migrationRules:["overwrite","schema-only"],filterTargetKey:"name",autoGenId:!1,createdAt:!0,createdBy:!0,updatedAt:!0,updatedBy:!0,fields:[{name:"name",type:"uid",prefix:"s_",primaryKey:!0,interface:"input",uiSchema:{type:"string",title:'{{t("Channel name")}}',"x-component":"Input",required:!0,description:"{{t('Randomly generated and can not be modified. Support letters, numbers and underscores, must start with an letter.')}}"}},{name:"title",type:"string",interface:"input",uiSchema:{type:"string","x-component":"Input",title:'{{t("Channel display name")}}',required:!0}},{name:"options",type:"json",interface:"json",uiSchema:{type:"object","x-component":"ConfigForm"}},{name:"meta",type:"json",interface:"json"},{interface:"input",type:"string",name:"notificationType",uiSchema:{type:"string",title:'{{t("Notification type")}}',"x-component":"Select",enum:"{{notificationTypeOptions}}",required:!0}},{name:"description",type:"text",interface:"textarea",uiSchema:{type:"string","x-component":"Input.TextArea",title:'{{t("Description")}}'}}]}},807:function(e,t,o){t.Z={name:o(296).O.logs,migrationRules:["schema-only"],title:"MessageLogs",fields:[{name:"id",type:"uuid",primaryKey:!0,allowNull:!1,interface:"uuid",uiSchema:{type:"string",title:'{{t("ID")}}',"x-component":"Input","x-read-pretty":!0}},{name:"channelName",type:"string",interface:"input",uiSchema:{type:"string",title:'{{t("Channel name")}}',"x-component":"Input"}},{name:"channelTitle",type:"string",interface:"input",uiSchema:{type:"string","x-component":"Input",title:'{{t("Channel display name")}}'}},{name:"triggerFrom",type:"string",interface:"input",uiSchema:{type:"string","x-component":"Input",title:'{{t("Trigger from")}}'}},{name:"notificationType",type:"string",interface:"input",uiSchema:{type:"string",title:'{{t("Notification type")}}',"x-component":"Select",enum:"{{notificationTypeOptions}}",required:!0}},{name:"status",type:"string",interface:"select",uiSchema:{type:"string","x-component":"Select",enum:[{label:'{{t("Success")}}',value:"success",color:"green"},{label:'{{t("Failure")}}',value:"failure",color:"red"}],title:'{{t("Status")}}'}},{name:"message",type:"json",interface:"json",uiSchema:{"x-component":"Input.JSON",title:'{{t("Message")}}',"x-component-props":{autoSize:{minRows:5}},autoSize:{minRows:5}}},{name:"reason",type:"text",interface:"input",uiSchema:{type:"string","x-component":"Input",title:'{{t("Failed reason")}}'}},{name:"createdAt",type:"date",interface:"createdAt",field:"createdAt",uiSchema:{type:"datetime",title:'{{t("Created at")}}',"x-component":"DatePicker","x-component-props":{},"x-read-pretty":!0}},{name:"updatedAt",type:"date",interface:"updatedAt",field:"updatedAt",uiSchema:{type:"datetime",title:'{{t("Last updated at")}}',"x-component":"DatePicker","x-component-props":{},"x-read-pretty":!0}}]}}}]);
@@ -1,10 +0,0 @@
1
- /**
2
- * This file is part of the NocoBase (R) project.
3
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
- * Authors: NocoBase Team.
5
- *
6
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
- * For more information, please refer to: https://www.nocobase.com/agreement.
8
- */
9
-
10
- "use strict";(self.webpackChunk_nocobase_plugin_notification_manager=self.webpackChunk_nocobase_plugin_notification_manager||[]).push([["843"],{709:function(e,t,n){n.r(t),n.d(t,{ChannelManager:function(){return S}});var o=n(482),r=n(772),i=n(721),c=n(156),a=n.n(c),p=n(712),l=n(807),s=n(551),u=n(765),m=n(655),d=n(875),y=n(296);function f(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{},o=Object.keys(n);"function"==typeof Object.getOwnPropertySymbols&&(o=o.concat(Object.getOwnPropertySymbols(n).filter(function(e){return Object.getOwnPropertyDescriptor(n,e).enumerable}))),o.forEach(function(t){var o;o=n[t],t in e?Object.defineProperty(e,t,{value:o,enumerable:!0,configurable:!0,writable:!0}):e[t]=o})}return e}function x(e,t){return t=null!=t?t:{},Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):(function(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);n.push.apply(n,o)}return n})(Object(t)).forEach(function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}),e}var b={type:"object",properties:{drawer:{type:"void","x-component":"Action.Drawer","x-decorator":"FormV2","x-use-decorator-props":"useCreateFormProps",title:'{{t("Add new")}}',properties:x(f({},{name:{"x-component":"CollectionField","x-decorator":"FormItem"},title:{"x-component":"CollectionField","x-decorator":"FormItem"},description:{"x-component":"CollectionField","x-decorator":"FormItem"},options:{"x-component":"CollectionField"}}),{footer:{type:"void","x-component":"Action.Drawer.Footer",properties:{cancel:{title:'{{t("Cancel")}}',"x-component":"Action","x-use-component-props":"useCloseActionProps"},submit:{title:'{{t("Submit")}}',"x-component":"Action","x-use-component-props":"useCreateActionProps"}}}})}}},h={type:"void",name:(0,d.uid)(),"x-decorator":"TableBlockProvider","x-decorator-props":{collection:y.O.channels,action:"list",dragSort:!1,params:{sort:["createdAt"],pageSize:20}},properties:{actions:{type:"void","x-component":"ActionBar","x-component-props":{style:{marginBottom:16}},properties:{refresh:{title:"{{t('Refresh')}}","x-action":"refresh","x-component":"Action","x-use-component-props":"useRefreshActionProps","x-component-props":{icon:"ReloadOutlined"}},create:{type:"void",title:'{{t("Add new")}}',"x-component":"AddNew","x-component-props":{type:"primary"}},filter:{"x-action":"filter",type:"object","x-component":"Filter.Action",title:"{{t('Filter')}}","x-use-component-props":"useFilterActionProps","x-component-props":{icon:"FilterOutlined"},"x-align":"left"}}},table:{type:"array","x-component":"TableV2","x-use-component-props":"useTableBlockProps","x-component-props":{rowKey:"name"},properties:{title:{type:"void","x-component":"TableV2.Column",title:'{{t("Channel display name")}}',"x-component-props":{width:100},properties:{title:{type:"string","x-component":"CollectionField","x-read-pretty":!0,"x-component-props":{ellipsis:!0}}}},name:{type:"void","x-component":"TableV2.Column",title:'{{t("Channel name")}}',"x-component-props":{width:100},properties:{name:{type:"string","x-component":"CollectionField","x-read-pretty":!0,"x-component-props":{ellipsis:!0}}}},description:{type:"void","x-component":"TableV2.Column",title:'{{t("Description")}}',"x-component-props":{width:200},properties:{description:{type:"boolean","x-component":"CollectionField","x-read-pretty":!0,"x-component-props":{ellipsis:!0}}}},notificationType:{title:'{{t("Notification type")}}',type:"void","x-component":"TableV2.Column","x-component-props":{width:200},properties:{notificationType:{type:"string","x-component":"CollectionField","x-read-pretty":!0}}},actions:{type:"void",title:'{{t("Actions")}}',"x-component":"TableV2.Column",properties:{edit:{type:"void",title:'{{t("Edit")}}',"x-component":"Action.Link","x-component-props":{openMode:"drawer"},"x-use-component-props":"useRecordEditActionProps","x-decorator":"Space",properties:{drawer:{type:"void",title:'{{t("Edit")}}',"x-component":"Action.Drawer","x-decorator":"FormV2","x-use-decorator-props":"useEditFormProps",properties:x(f({},{name:{"x-component":"CollectionField","x-decorator":"FormItem","x-disabled":!0},title:{"x-component":"CollectionField","x-decorator":"FormItem"},description:{"x-component":"CollectionField","x-decorator":"FormItem"},options:{"x-component":"CollectionField"}}),{footer:{type:"void","x-component":"Action.Drawer.Footer",properties:{cancel:{title:'{{t("Cancel")}}',"x-component":"Action","x-use-component-props":"useCloseActionProps"},submit:{title:"Submit","x-component":"Action","x-use-component-props":"useEditActionProps"}}}})}}},delete:{type:"void",title:'{{t("Delete")}}',"x-decorator":"Space","x-component":"Action.Link","x-use-component-props":"useRecordDeleteActionProps","x-component-props":{confirm:{title:"{{t('Delete record')}}",content:"{{t('Are you sure you want to delete it?')}}"}}}}}}}}},g=n(505),v=(0,g.observer)(function(){var e,t,n=(0,g.useForm)(),o=(0,r.useCollectionRecord)(),i=n.values.notificationType||(null==o||null==(e=o.data)?void 0:e.notificationType),p=(0,c.useContext)(u.wi).channelTypes.find(function(e){return e.type===i});return(null==(t=p.components)?void 0:t.ChannelConfigForm)?a().createElement(p.components.ChannelConfigForm,null):null},{displayName:"ConfigForm"});function C(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,o=Array(t);n<t;n++)o[n]=e[n];return o}function P(e,t,n,o,r,i,c){try{var a=e[i](c),p=a.value}catch(e){n(e);return}a.done?t(p):Promise.resolve(p).then(o,r)}var w=function(){var e=(0,r.useActionContext)().setVisible;return{run:function(){var t;return(t=function(){return function(e,t){var n,o,r,i,c={label:0,sent:function(){if(1&r[0])throw r[1];return r[1]},trys:[],ops:[]};return i={next:a(0),throw:a(1),return:a(2)},"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function a(i){return function(a){var p=[i,a];if(n)throw TypeError("Generator is already executing.");for(;c;)try{if(n=1,o&&(r=2&p[0]?o.return:p[0]?o.throw||((r=o.return)&&r.call(o),0):o.next)&&!(r=r.call(o,p[1])).done)return r;switch(o=0,r&&(p=[2&p[0],r.value]),p[0]){case 0:case 1:r=p;break;case 4:return c.label++,{value:p[1],done:!1};case 5:c.label++,o=p[1],p=[0];continue;case 7:p=c.ops.pop(),c.trys.pop();continue;default:if(!(r=(r=c.trys).length>0&&r[r.length-1])&&(6===p[0]||2===p[0])){c=0;continue}if(3===p[0]&&(!r||p[1]>r[0]&&p[1]<r[3])){c.label=p[1];break}if(6===p[0]&&c.label<r[1]){c.label=r[1],r=p;break}if(r&&c.label<r[2]){c.label=r[2],c.ops.push(p);break}r[2]&&c.ops.pop(),c.trys.pop();continue}p=t.call(e,c)}catch(e){p=[6,e],o=0}finally{n=r=0}if(5&p[0])throw p[1];return{value:p[0]?p[1]:void 0,done:!0}}}}(this,function(t){return e(!1),[2]})},function(){var e=this,n=arguments;return new Promise(function(o,r){var i=t.apply(e,n);function c(e){P(i,o,r,c,a,"next",e)}function a(e){P(i,o,r,c,a,"throw",e)}c(void 0)})})()}}},A=function(){var e,t=(0,s.oG)().t,n=(e=(0,c.useState)(!1),function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n,o,r=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=r){var i=[],c=!0,a=!1;try{for(r=r.call(e);!(c=(n=r.next()).done)&&(i.push(n.value),i.length!==t);c=!0);}catch(e){a=!0,o=e}finally{try{c||null==r.return||r.return()}finally{if(a)throw o}}return i}}(e,2)||function(e,t){if(e){if("string"==typeof e)return C(e,2);var n=Object.prototype.toString.call(e).slice(8,-1);if("Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n)return Array.from(n);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return C(e,t)}}(e,2)||function(){throw TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()),p=n[0],l=n[1],d=(0,u.tZ)(),y=d.NotificationTypeNameProvider,f=(d.name,d.setName),x=(0,r.useAPIClient)(),h=(0,u.CZ)().filter(function(e){var t;return(null==(t=e.meta)?void 0:t.creatable)!==!1}),g=0===h.length?[{key:"__empty__",label:a().createElement(i.Empty,{image:i.Empty.PRESENTED_IMAGE_SIMPLE,description:a().createElement(a().Fragment,null,t("No channel enabled yet"),a().createElement("br",null)," ",a().createElement("a",{target:"_blank",href:"zh-CN"===x.auth.locale?"https://docs-cn.nocobase.com/handbook/notification-manager":"https://docs.nocobase.com/handbook/notification-manager",rel:"noreferrer"},t("View documentation")))})}]:h.map(function(e){return{key:e.type,label:e.title,onClick:function(){l(!0),f(e.type)}}});return a().createElement(r.ActionContextProvider,{value:{visible:p,setVisible:l}},a().createElement(y,null,a().createElement(i.Dropdown,{menu:{items:g}},a().createElement(i.Button,{icon:a().createElement(o.PlusOutlined,null),type:"primary"},t("Add new")," ",a().createElement(o.DownOutlined,null))),a().createElement(r.SchemaComponent,{scope:{useCloseAction:w,useCreateActionProps:m.cD,useEditActionProps:m.G8,useCloseActionProps:m.Uy,useEditFormProps:m.fC,useCreateFormProps:m.Uc},schema:b})))},O=function(){return(0,r.useAsyncData)().data,!1},S=function(){var e=(0,s.oG)().t,t=(0,m.aT)(),n=(0,r.useSchemaComponentContext)(),o=(0,c.useMemo)(function(){var e,t;return e=function(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{},o=Object.keys(n);"function"==typeof Object.getOwnPropertySymbols&&(o=o.concat(Object.getOwnPropertySymbols(n).filter(function(e){return Object.getOwnPropertyDescriptor(n,e).enumerable}))),o.forEach(function(t){var o;o=n[t],t in e?Object.defineProperty(e,t,{value:o,enumerable:!0,configurable:!0,writable:!0}):e[t]=o})}return e}({},n),t=t={designable:!1},Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):(function(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);n.push.apply(n,o)}return n})(Object(t)).forEach(function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}),e},[n]);return a().createElement(r.ExtendCollectionsProvider,{collections:[p.Z,l.Z]},a().createElement(r.SchemaComponentContext.Provider,{value:o},a().createElement(u.wi.Provider,{value:{channelTypes:t}},a().createElement(i.Card,{bordered:!1},a().createElement(r.SchemaComponent,{schema:h,components:{AddNew:A,ConfigForm:v},scope:{useCanNotDelete:O,t:e,notificationTypeOptions:t,useCreateActionProps:m.cD,useEditActionProps:m.G8,useCloseActionProps:m.Uy,useEditFormProps:m.fC,useCreateFormProps:m.Uc,useRecordDeleteActionProps:m.$l,useRecordEditActionProps:m.Bj}})))))};S.displayName="ChannelManager"},712:function(e,t,n){t.Z={name:n(296).O.channels,migrationRules:["overwrite","schema-only"],filterTargetKey:"name",autoGenId:!1,createdAt:!0,createdBy:!0,updatedAt:!0,updatedBy:!0,fields:[{name:"name",type:"uid",prefix:"s_",primaryKey:!0,interface:"input",uiSchema:{type:"string",title:'{{t("Channel name")}}',"x-component":"Input",required:!0,description:"{{t('Randomly generated and can not be modified. Support letters, numbers and underscores, must start with an letter.')}}"}},{name:"title",type:"string",interface:"input",uiSchema:{type:"string","x-component":"Input",title:'{{t("Channel display name")}}',required:!0}},{name:"options",type:"json",interface:"json",uiSchema:{type:"object","x-component":"ConfigForm"}},{name:"meta",type:"json",interface:"json"},{interface:"input",type:"string",name:"notificationType",uiSchema:{type:"string",title:'{{t("Notification type")}}',"x-component":"Select",enum:"{{notificationTypeOptions}}",required:!0}},{name:"description",type:"text",interface:"textarea",uiSchema:{type:"string","x-component":"Input.TextArea",title:'{{t("Description")}}'}}]}},807:function(e,t,n){t.Z={name:n(296).O.logs,migrationRules:["schema-only"],title:"MessageLogs",fields:[{name:"id",type:"uuid",primaryKey:!0,allowNull:!1,interface:"uuid",uiSchema:{type:"string",title:'{{t("ID")}}',"x-component":"Input","x-read-pretty":!0}},{name:"channelName",type:"string",interface:"input",uiSchema:{type:"string",title:'{{t("Channel name")}}',"x-component":"Input"}},{name:"channelTitle",type:"string",interface:"input",uiSchema:{type:"string","x-component":"Input",title:'{{t("Channel display name")}}'}},{name:"triggerFrom",type:"string",interface:"input",uiSchema:{type:"string","x-component":"Input",title:'{{t("Trigger from")}}'}},{name:"notificationType",type:"string",interface:"input",uiSchema:{type:"string",title:'{{t("Notification type")}}',"x-component":"Select",enum:"{{notificationTypeOptions}}",required:!0}},{name:"status",type:"string",interface:"select",uiSchema:{type:"string","x-component":"Select",enum:[{label:'{{t("Success")}}',value:"success",color:"green"},{label:'{{t("Failure")}}',value:"failure",color:"red"}],title:'{{t("Status")}}'}},{name:"message",type:"json",interface:"json",uiSchema:{"x-component":"Input.JSON",title:'{{t("Message")}}',"x-component-props":{autoSize:{minRows:5}},autoSize:{minRows:5}}},{name:"reason",type:"text",interface:"input",uiSchema:{type:"string","x-component":"Input",title:'{{t("Failed reason")}}'}},{name:"createdAt",type:"date",interface:"createdAt",field:"createdAt",uiSchema:{type:"datetime",title:'{{t("Created at")}}',"x-component":"DatePicker","x-component-props":{},"x-read-pretty":!0}},{name:"updatedAt",type:"date",interface:"updatedAt",field:"updatedAt",uiSchema:{type:"datetime",title:'{{t("Last updated at")}}',"x-component":"DatePicker","x-component-props":{},"x-read-pretty":!0}}]}}}]);