@inspirer-dev/crm-dashboard 1.0.80 → 1.0.82

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 (46) hide show
  1. package/admin/src/components/ButtonsBuilder/index.tsx +3 -3
  2. package/admin/src/components/CancelConditionsField/index.tsx +7 -6
  3. package/admin/src/components/RulesBuilder/index.tsx +9 -8
  4. package/admin/src/components/StepFlowBuilder/constants.ts +2 -0
  5. package/admin/src/components/StepFlowBuilder/index.tsx +1 -1
  6. package/admin/src/components/StepFlowBuilder/nodes/EventTriggerNode.tsx +29 -1
  7. package/admin/src/components/StepFlowBuilder/panels/EventTriggerConfig.tsx +97 -9
  8. package/admin/src/components/StepFlowBuilder/panels/NodeEditPanel.tsx +1 -1
  9. package/admin/src/components/StepFlowBuilder/panels/WaitConfig.tsx +1 -3
  10. package/admin/src/components/StepFlowBuilder/types.ts +2 -0
  11. package/admin/src/components/TriggerConfigField/index.tsx +11 -10
  12. package/admin/src/components/TriggerParamsField/constants.ts +109 -0
  13. package/admin/src/components/TriggerParamsField/index.tsx +292 -0
  14. package/admin/src/index.ts +26 -1
  15. package/admin/src/pages/HomePage/components/CampaignBuilder/index.tsx +4 -0
  16. package/admin/src/pages/HomePage/components/FlowBuilderTest.tsx +3 -3
  17. package/admin/src/pages/HomePage/components/SendTimeHeatMap.tsx +2 -2
  18. package/admin/src/pages/HomePage/components/StatsView.tsx +2 -2
  19. package/admin/src/translations/en.json +4 -1
  20. package/admin/src/translations/ru.json +4 -1
  21. package/admin/tsconfig.json +12 -1
  22. package/admin/tsconfig.tsbuildinfo +1 -1
  23. package/dist/_chunks/{en-DEUgX5uV.mjs → en-B5BgIROW.mjs} +3 -1
  24. package/dist/_chunks/{en-D2kTkBns.js → en-GKZo4lia.js} +3 -1
  25. package/dist/_chunks/{index-C-1xCfqJ.js → index-354YMebI.js} +152 -38
  26. package/dist/_chunks/{index-BydXrDhA.mjs → index-BKfFI_Jo.mjs} +2 -2
  27. package/dist/_chunks/{index-D1kMmlrA.js → index-BQcRoIJr.js} +5 -4
  28. package/dist/_chunks/{index-BJzk6xNb.mjs → index-BgwX1xYS.mjs} +7 -6
  29. package/dist/_chunks/{index-pJUyH-Qr.js → index-Cg0G_bTE.js} +2 -2
  30. package/dist/_chunks/index-CuMY0eo5.js +310 -0
  31. package/dist/_chunks/{index-unxa4Q_H.mjs → index-DKJtyGq7.mjs} +5 -4
  32. package/dist/_chunks/{index-BFRbyVHC.js → index-DRXMKPXI.js} +1 -1
  33. package/dist/_chunks/{index-Xa_4jez0.mjs → index-Dhj0KzCX.mjs} +5 -4
  34. package/dist/_chunks/{index-Dv1tGmDT.mjs → index-LXBoz7PC.mjs} +1 -1
  35. package/dist/_chunks/index-NvFKi6er.mjs +310 -0
  36. package/dist/_chunks/{index-BKrTVHBr.js → index-T7VXjklK.js} +5 -4
  37. package/dist/_chunks/{index-CWSibOAr.mjs → index-gR86Z3uh.mjs} +152 -38
  38. package/dist/_chunks/{index-CAwynvu7.js → index-xDSMnUMp.js} +7 -6
  39. package/dist/_chunks/{ru-BKzplvmu.js → ru-bj5iiIPr.js} +3 -1
  40. package/dist/_chunks/{ru-DOt1yfNm.mjs → ru-h22ZdPCS.mjs} +3 -1
  41. package/dist/admin/index.js +31 -7
  42. package/dist/admin/index.mjs +32 -8
  43. package/dist/server/index.js +5 -0
  44. package/dist/server/index.mjs +5 -0
  45. package/package.json +3 -3
  46. package/server/src/register.ts +6 -0
@@ -0,0 +1,292 @@
1
+ import React, { forwardRef, useEffect, useMemo, useState } from 'react';
2
+ import {
3
+ Box,
4
+ Button,
5
+ Field,
6
+ Flex,
7
+ IconButton,
8
+ NumberInput,
9
+ Typography,
10
+ SingleSelect,
11
+ SingleSelectOption,
12
+ Card,
13
+ CardContent,
14
+ Tooltip,
15
+ } from '@strapi/design-system';
16
+ import { Plus, Trash } from '@strapi/icons';
17
+ import { useTheme } from 'styled-components';
18
+ import { TRIGGER_PARAMS, STAGE_TYPE_LABELS, type TriggerParamDef } from './constants';
19
+
20
+ type TriggerParamsValue = Record<string, number | undefined>;
21
+
22
+ interface TriggerParamsFieldProps {
23
+ name: string;
24
+ value?: string | TriggerParamsValue | null;
25
+ onChange: (event: { target: { name: string; value: string } }) => void;
26
+ intlLabel: {
27
+ id: string;
28
+ defaultMessage: string;
29
+ };
30
+ attribute?: unknown;
31
+ disabled?: boolean;
32
+ error?: string;
33
+ required?: boolean;
34
+ hint?: string;
35
+ }
36
+
37
+ const parseValue = (value: string | TriggerParamsValue | null | undefined): TriggerParamsValue => {
38
+ if (!value) return {};
39
+ if (typeof value === 'object' && !Array.isArray(value)) return value as TriggerParamsValue;
40
+ if (typeof value === 'string') {
41
+ try {
42
+ const parsed = JSON.parse(value);
43
+ if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) return parsed;
44
+ } catch {}
45
+ }
46
+ return {};
47
+ };
48
+
49
+ const serialize = (params: TriggerParamsValue): string => {
50
+ const clean: Record<string, number> = {};
51
+ for (const [key, val] of Object.entries(params)) {
52
+ if (val !== undefined && val !== null) {
53
+ clean[key] = val;
54
+ }
55
+ }
56
+ return JSON.stringify(clean);
57
+ };
58
+
59
+ interface StrapiTheme {
60
+ colors?: Record<string, string>;
61
+ }
62
+
63
+ const useThemeColors = () => {
64
+ const theme = useTheme() as unknown as StrapiTheme;
65
+ const isDark = theme?.colors?.neutral0 === '#212134';
66
+
67
+ return useMemo(
68
+ () => ({
69
+ isDark,
70
+ emptyBorder: isDark ? '#32324d' : '#dcdce4',
71
+ cardBorder: isDark ? '#32324d' : '#eaeaef',
72
+ tagBg: isDark ? '#2d2d4a' : '#f0f0ff',
73
+ }),
74
+ [isDark]
75
+ );
76
+ };
77
+
78
+ const TriggerParamsField = forwardRef<HTMLDivElement, TriggerParamsFieldProps>(
79
+ ({ name, value, onChange, intlLabel, disabled, error, required, hint }, ref) => {
80
+ const [params, setParams] = useState<TriggerParamsValue>(() => parseValue(value));
81
+ const colors = useThemeColors();
82
+
83
+ useEffect(() => {
84
+ setParams(parseValue(value));
85
+ }, [value]);
86
+
87
+ const update = (next: TriggerParamsValue) => {
88
+ setParams(next);
89
+ onChange({ target: { name, value: serialize(next) } });
90
+ };
91
+
92
+ const activeKeys = Object.keys(params).filter(
93
+ (k) => params[k] !== undefined && params[k] !== null
94
+ );
95
+
96
+ const availableParams = TRIGGER_PARAMS.filter((p) => !activeKeys.includes(p.key));
97
+
98
+ const addParam = (key: string) => {
99
+ const def = TRIGGER_PARAMS.find((p) => p.key === key);
100
+ if (!def) return;
101
+ update({ ...params, [key]: undefined });
102
+ };
103
+
104
+ const removeParam = (key: string) => {
105
+ const next = { ...params };
106
+ delete next[key];
107
+ update(next);
108
+ };
109
+
110
+ const setParamValue = (key: string, val: number | undefined) => {
111
+ update({ ...params, [key]: val });
112
+ };
113
+
114
+ const getParamDef = (key: string): TriggerParamDef | undefined =>
115
+ TRIGGER_PARAMS.find((p) => p.key === key);
116
+
117
+ return (
118
+ <Field.Root name={name} error={error} required={required} hint={hint} ref={ref}>
119
+ <Flex direction="column" gap={3}>
120
+ <Flex justifyContent="space-between" alignItems="center">
121
+ <Box>
122
+ <Field.Label>{intlLabel?.defaultMessage || 'Trigger Params'}</Field.Label>
123
+ <Typography variant="pi" textColor="neutral500">
124
+ Настройте параметры срабатывания для этого этапа
125
+ </Typography>
126
+ </Box>
127
+ </Flex>
128
+
129
+ {activeKeys.length === 0 ? (
130
+ <Box
131
+ padding={5}
132
+ background="neutral100"
133
+ hasRadius
134
+ style={{
135
+ border: `2px dashed ${colors.emptyBorder}`,
136
+ textAlign: 'center',
137
+ }}
138
+ >
139
+ <Typography variant="omega" textColor="neutral500">
140
+ Параметры не настроены
141
+ </Typography>
142
+ <Typography
143
+ variant="pi"
144
+ textColor="neutral400"
145
+ style={{ display: 'block', marginTop: 4 }}
146
+ >
147
+ Добавьте параметры триггера, чтобы управлять условиями показа этапа
148
+ </Typography>
149
+ </Box>
150
+ ) : (
151
+ <Flex direction="column" gap={2}>
152
+ {activeKeys.map((key) => {
153
+ const def = getParamDef(key);
154
+ if (!def) return null;
155
+
156
+ return (
157
+ <Card
158
+ key={key}
159
+ background="neutral0"
160
+ style={{
161
+ border: `1px solid ${colors.cardBorder}`,
162
+ }}
163
+ >
164
+ <CardContent>
165
+ <Flex gap={3} alignItems="center" padding={3}>
166
+ <Box style={{ flex: 1, minWidth: 0 }}>
167
+ <Flex gap={2} alignItems="center" marginBottom={1}>
168
+ <Typography variant="omega" fontWeight="semiBold">
169
+ {def.label}
170
+ </Typography>
171
+ {def.unit && (
172
+ <Typography variant="pi" textColor="neutral500">
173
+ ({def.unit})
174
+ </Typography>
175
+ )}
176
+ </Flex>
177
+ <Typography variant="pi" textColor="neutral500">
178
+ {def.description}
179
+ </Typography>
180
+ <Flex gap={1} marginTop={1} wrap="wrap">
181
+ {def.stageTypes.map((st) => (
182
+ <Box
183
+ key={st}
184
+ style={{
185
+ padding: '1px 6px',
186
+ borderRadius: '4px',
187
+ backgroundColor: colors.tagBg,
188
+ fontSize: '11px',
189
+ }}
190
+ >
191
+ <Typography variant="pi" textColor="primary600">
192
+ {STAGE_TYPE_LABELS[st] || st}
193
+ </Typography>
194
+ </Box>
195
+ ))}
196
+ </Flex>
197
+ </Box>
198
+
199
+ <Box style={{ width: 120, flexShrink: 0 }}>
200
+ <NumberInput
201
+ placeholder={def.placeholder}
202
+ value={params[key] ?? ''}
203
+ onValueChange={(val: number | undefined) => setParamValue(key, val)}
204
+ disabled={disabled}
205
+ size="S"
206
+ step={key === 'balanceThresholdMultiplier' ? 0.1 : 1}
207
+ />
208
+ </Box>
209
+
210
+ <Tooltip label="Удалить параметр">
211
+ <IconButton
212
+ onClick={() => removeParam(key)}
213
+ label="Delete"
214
+ variant="ghost"
215
+ size="S"
216
+ disabled={disabled}
217
+ style={{ color: '#d02b20', flexShrink: 0 }}
218
+ >
219
+ <Trash width={16} height={16} />
220
+ </IconButton>
221
+ </Tooltip>
222
+ </Flex>
223
+ </CardContent>
224
+ </Card>
225
+ );
226
+ })}
227
+ </Flex>
228
+ )}
229
+
230
+ {availableParams.length > 0 && (
231
+ <AddParamSelect
232
+ available={availableParams}
233
+ onAdd={addParam}
234
+ disabled={disabled}
235
+ />
236
+ )}
237
+
238
+ {error && <Field.Error />}
239
+ {hint && <Field.Hint />}
240
+ </Flex>
241
+ </Field.Root>
242
+ );
243
+ }
244
+ );
245
+
246
+ TriggerParamsField.displayName = 'TriggerParamsField';
247
+
248
+ interface AddParamSelectProps {
249
+ available: TriggerParamDef[];
250
+ onAdd: (key: string) => void;
251
+ disabled?: boolean;
252
+ }
253
+
254
+ const AddParamSelect: React.FC<AddParamSelectProps> = ({ available, onAdd, disabled }) => {
255
+ const [selected, setSelected] = useState<string | null>(null);
256
+
257
+ return (
258
+ <Flex gap={2} alignItems="flex-end">
259
+ <Box style={{ flex: 1 }}>
260
+ <SingleSelect
261
+ placeholder="Выберите параметр..."
262
+ value={selected}
263
+ onChange={(val: string) => setSelected(val)}
264
+ disabled={disabled}
265
+ size="S"
266
+ >
267
+ {available.map((p) => (
268
+ <SingleSelectOption key={p.key} value={p.key}>
269
+ {p.label} — {p.description}
270
+ </SingleSelectOption>
271
+ ))}
272
+ </SingleSelect>
273
+ </Box>
274
+ <Button
275
+ startIcon={<Plus />}
276
+ onClick={() => {
277
+ if (selected) {
278
+ onAdd(selected);
279
+ setSelected(null);
280
+ }
281
+ }}
282
+ disabled={disabled || !selected}
283
+ variant="secondary"
284
+ size="S"
285
+ >
286
+ Добавить
287
+ </Button>
288
+ </Flex>
289
+ );
290
+ };
291
+
292
+ export default TriggerParamsField;
@@ -1,4 +1,4 @@
1
- import { Message, Clock, Cross, Link, ArrowRight } from '@strapi/icons';
1
+ import { Message, Clock, Cross, Link, ArrowRight, Filter } from '@strapi/icons';
2
2
 
3
3
  const PLUGIN_ID = 'crm-dashboard';
4
4
 
@@ -129,6 +129,31 @@ export default {
129
129
  },
130
130
  });
131
131
 
132
+ app.customFields.register({
133
+ name: 'trigger-params',
134
+ pluginId: PLUGIN_ID,
135
+ type: 'json',
136
+ intlLabel: {
137
+ id: `${PLUGIN_ID}.trigger-params.label`,
138
+ defaultMessage: 'Trigger Params',
139
+ },
140
+ intlDescription: {
141
+ id: `${PLUGIN_ID}.trigger-params.description`,
142
+ defaultMessage: 'Configure trigger parameters for popup flow stages',
143
+ },
144
+ icon: Filter,
145
+ components: {
146
+ Input: async () =>
147
+ import(
148
+ /* webpackChunkName: "crm-trigger-params" */ './components/TriggerParamsField/index'
149
+ ),
150
+ },
151
+ options: {
152
+ base: [],
153
+ advanced: [],
154
+ },
155
+ });
156
+
132
157
  app.addMenuLink({
133
158
  to: `/plugins/${PLUGIN_ID}`,
134
159
  icon: Message,
@@ -331,6 +331,8 @@ const CampaignBuilder: React.FC = () => {
331
331
  <Field.Root>
332
332
  <Flex gap={2} alignItems="center">
333
333
  <Toggle
334
+ onLabel=""
335
+ offLabel=""
334
336
  checked={editingCampaign.isActive}
335
337
  onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
336
338
  handleFieldChange('isActive', e.target.checked)
@@ -342,6 +344,8 @@ const CampaignBuilder: React.FC = () => {
342
344
  <Field.Root>
343
345
  <Flex gap={2} alignItems="center">
344
346
  <Toggle
347
+ onLabel=""
348
+ offLabel=""
345
349
  checked={editingCampaign.ignoreQuietHours}
346
350
  onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
347
351
  handleFieldChange('ignoreQuietHours', e.target.checked)
@@ -13,8 +13,8 @@ const SAMPLE_STEPS: FlowStep[] = [
13
13
  order: 0,
14
14
  channel: 'telegram',
15
15
  variants: [
16
- { name: 'Variant A', template: { id: 1, name: 'Welcome Template' }, weight: 50 },
17
- { name: 'Variant B', template: { id: 2, name: 'Welcome V2' }, weight: 50 },
16
+ { name: 'Variant A', template: { id: 1, documentId: '1', name: 'Welcome Template' }, weight: 50 },
17
+ { name: 'Variant B', template: { id: 2, documentId: '2', name: 'Welcome V2' }, weight: 50 },
18
18
  ],
19
19
  nextStep: 'step_wait',
20
20
  },
@@ -32,7 +32,7 @@ const SAMPLE_STEPS: FlowStep[] = [
32
32
  name: 'Check Activity',
33
33
  stepType: 'branch',
34
34
  order: 2,
35
- branchSegment: { id: 1, name: 'Active Users' },
35
+ branchSegment: { id: 1, documentId: '1', name: 'Active Users' },
36
36
  yesNextStep: 'step_active',
37
37
  noNextStep: 'step_inactive',
38
38
  },
@@ -20,8 +20,8 @@ const SendTimeHeatMap: React.FC<SendTimeHeatMapProps> = ({ filters }) => {
20
20
  const { data, isLoading } = useSendTimeData(filters);
21
21
 
22
22
  const gridMap = useMemo(() => {
23
- if (!data?.grid) return new Map<string, typeof data.grid[0]>();
24
- const map = new Map<string, typeof data.grid[0]>();
23
+ if (!data?.grid) return new Map();
24
+ const map = new Map<string, (typeof data.grid)[0]>();
25
25
  for (const cell of data.grid) {
26
26
  map.set(`${cell.day}-${cell.hour}`, cell);
27
27
  }
@@ -17,7 +17,7 @@ import {
17
17
  ActiveFilterChips,
18
18
  FilterChip,
19
19
  } from '../../../components/Filters';
20
- import { useFilterOptions, useDashboardStats, StatsFilters, TimeGranularity } from '../../../hooks/api';
20
+ import { useFilterOptions, useDashboardStats, StatsFilters, TimeGranularity, DashboardTotals } from '../../../hooks/api';
21
21
  import { SendChart, AntiSpamChart, ConversionFunnelChart, TopCampaignsChart } from './charts';
22
22
  import { exportStats, ExportFormat } from '../../../utils/exportStats';
23
23
  import TodayWidget from './TodayWidget';
@@ -422,7 +422,7 @@ const StatsView: React.FC = () => {
422
422
  return chips;
423
423
  }, [filters, campaigns, segments]);
424
424
 
425
- const totals = stats?.totals || { sent: 0, clicks: 0, click_rate: 0, deposits_1h: 0, deposit_sum_1h: 0, deposit_rate: 0 };
425
+ const totals: DashboardTotals = stats?.totals || { sent: 0, clicks: 0, unique_clickers: 0, click_rate: 0, deposits_1h: 0, deposit_sum_1h: 0, deposit_rate: 0, unique_users_sent: 0 };
426
426
  const previousTotals = stats?.previous_totals;
427
427
  const funnel = stats?.funnel;
428
428
  const timeSeries = stats?.time_series || [];
@@ -119,5 +119,8 @@
119
119
  "crm-dashboard.template.title.description": "For email: subject line. For Telegram: optional internal title (not shown to user). For push: notification title.",
120
120
 
121
121
  "crm-dashboard.template.body.label": "Message Body",
122
- "crm-dashboard.template.body.description": "The message text. Variables: {{userName}}, {{balance}}, {{depositCount}}, {{depositTotal}}, {{amount}}. Markdown: *bold*, _italic_"
122
+ "crm-dashboard.template.body.description": "The message text. Variables: {{userName}}, {{balance}}, {{depositCount}}, {{depositTotal}}, {{amount}}. Markdown: *bold*, _italic_",
123
+
124
+ "crm-dashboard.trigger-params.label": "Trigger Params",
125
+ "crm-dashboard.trigger-params.description": "Configure trigger parameters for popup flow stages. Add only the parameters relevant to this stage type."
123
126
  }
@@ -119,5 +119,8 @@
119
119
  "crm-dashboard.template.title.description": "Для email: тема письма. Для Telegram: внутренний заголовок (не виден пользователю). Для push: заголовок уведомления.",
120
120
 
121
121
  "crm-dashboard.template.body.label": "Текст сообщения",
122
- "crm-dashboard.template.body.description": "Текст сообщения. Переменные: {{userName}}, {{balance}}, {{depositCount}}, {{depositTotal}}, {{amount}}. Markdown: *жирный*, _курсив_"
122
+ "crm-dashboard.template.body.description": "Текст сообщения. Переменные: {{userName}}, {{balance}}, {{depositCount}}, {{depositTotal}}, {{amount}}. Markdown: *жирный*, _курсив_",
123
+
124
+ "crm-dashboard.trigger-params.label": "Параметры триггера",
125
+ "crm-dashboard.trigger-params.description": "Настройте параметры срабатывания для этапов popup-флоу. Добавляйте только параметры, релевантные для данного типа этапа."
123
126
  }
@@ -1,6 +1,17 @@
1
1
  {
2
- "extends": "../../../../tsconfig.json",
3
2
  "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "ESNext",
5
+ "moduleResolution": "Bundler",
6
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
7
+ "jsx": "react-jsx",
8
+ "strict": true,
9
+ "skipLibCheck": true,
10
+ "esModuleInterop": true,
11
+ "resolveJsonModule": true,
12
+ "forceConsistentCasingInFileNames": true,
13
+ "noEmit": true,
14
+ "types": ["react", "react-dom"],
4
15
  "outDir": "dist",
5
16
  "rootDir": "src"
6
17
  },
@@ -1 +1 @@
1
- {"program":{"fileNames":[],"fileInfos":[],"root":[],"options":{"esModuleInterop":true,"module":1,"noEmitOnError":true,"noImplicitThis":true,"outDir":"./dist","rootDir":"./src","skipLibCheck":true,"strict":false,"target":6},"referencedMap":[],"exportedModulesMap":[]},"version":"5.4.4"}
1
+ {"fileNames":[],"fileInfos":[],"root":[],"options":{"esModuleInterop":true,"module":1,"noEmitOnError":true,"noImplicitThis":true,"outDir":"./dist","rootDir":"./src","skipLibCheck":true,"strict":false,"target":6},"errors":true,"version":"5.8.3"}
@@ -79,7 +79,9 @@ const en = {
79
79
  "crm-dashboard.template.title.label": "Title",
80
80
  "crm-dashboard.template.title.description": "For email: subject line. For Telegram: optional internal title (not shown to user). For push: notification title.",
81
81
  "crm-dashboard.template.body.label": "Message Body",
82
- "crm-dashboard.template.body.description": "The message text. Variables: {{userName}}, {{balance}}, {{depositCount}}, {{depositTotal}}, {{amount}}. Markdown: *bold*, _italic_"
82
+ "crm-dashboard.template.body.description": "The message text. Variables: {{userName}}, {{balance}}, {{depositCount}}, {{depositTotal}}, {{amount}}. Markdown: *bold*, _italic_",
83
+ "crm-dashboard.trigger-params.label": "Trigger Params",
84
+ "crm-dashboard.trigger-params.description": "Configure trigger parameters for popup flow stages. Add only the parameters relevant to this stage type."
83
85
  };
84
86
  export {
85
87
  en as default
@@ -81,6 +81,8 @@ const en = {
81
81
  "crm-dashboard.template.title.label": "Title",
82
82
  "crm-dashboard.template.title.description": "For email: subject line. For Telegram: optional internal title (not shown to user). For push: notification title.",
83
83
  "crm-dashboard.template.body.label": "Message Body",
84
- "crm-dashboard.template.body.description": "The message text. Variables: {{userName}}, {{balance}}, {{depositCount}}, {{depositTotal}}, {{amount}}. Markdown: *bold*, _italic_"
84
+ "crm-dashboard.template.body.description": "The message text. Variables: {{userName}}, {{balance}}, {{depositCount}}, {{depositTotal}}, {{amount}}. Markdown: *bold*, _italic_",
85
+ "crm-dashboard.trigger-params.label": "Trigger Params",
86
+ "crm-dashboard.trigger-params.description": "Configure trigger parameters for popup flow stages. Add only the parameters relevant to this stage type."
85
87
  };
86
88
  exports.default = en;