windmill-components 1.430.5 → 1.433.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 (35) hide show
  1. package/package/components/AppConnectInner.svelte +27 -2
  2. package/package/components/ConfirmButton.svelte +31 -0
  3. package/package/components/ConfirmButton.svelte.d.ts +20 -0
  4. package/package/components/DiffEditor.svelte +0 -6
  5. package/package/components/FlowStatusViewerInner.svelte +8 -4
  6. package/package/components/InstanceSettings.svelte +20 -1
  7. package/package/components/Login.svelte +31 -6
  8. package/package/components/ServiceLogsInner.svelte +365 -337
  9. package/package/components/apps/components/buttons/AppSchemaForm.svelte +1 -1
  10. package/package/components/apps/components/display/AppNavbarItem.svelte +1 -1
  11. package/package/components/apps/components/helpers/RunnableComponent.svelte +2 -2
  12. package/package/components/apps/components/inputs/AppS3FileInput.svelte +1 -1
  13. package/package/components/apps/editor/AppEditor.svelte +18 -8
  14. package/package/components/apps/editor/AppEditor.svelte.d.ts +5 -0
  15. package/package/components/apps/editor/AppEditorHeader.svelte +58 -58
  16. package/package/components/apps/editor/AppEditorHeader.svelte.d.ts +2 -0
  17. package/package/components/apps/editor/AppPreview.svelte +6 -1
  18. package/package/components/apps/editor/AppReportsDrawer.svelte +3 -613
  19. package/package/components/apps/editor/AppReportsDrawerInner.svelte +622 -0
  20. package/package/components/apps/editor/AppReportsDrawerInner.svelte.d.ts +17 -0
  21. package/package/components/apps/editor/component/components.d.ts +79 -79
  22. package/package/components/apps/editor/inlineScriptsPanel/EmptyInlineScript.svelte +1 -1
  23. package/package/components/apps/editor/inlineScriptsPanel/InlineScriptEditor.svelte +1 -1
  24. package/package/components/apps/editor/settingsPanel/GridNavbar.svelte +1 -1
  25. package/package/components/apps/types.d.ts +1 -1
  26. package/package/components/splitPanes/SplitPanesOrColumnOnMobile.svelte +34 -0
  27. package/package/components/splitPanes/SplitPanesOrColumnOnMobile.svelte.d.ts +23 -0
  28. package/package/components/wizards/AppPicker.svelte +4 -4
  29. package/package/gen/core/OpenAPI.js +1 -1
  30. package/package/gen/schemas.gen.d.ts +2 -2
  31. package/package/gen/schemas.gen.js +2 -2
  32. package/package/gen/services.gen.d.ts +0 -1
  33. package/package/gen/services.gen.js +0 -2
  34. package/package/gen/types.gen.d.ts +2 -4
  35. package/package.json +5 -5
@@ -0,0 +1,622 @@
1
+ <script>import { enterpriseLicense } from '../../../stores';
2
+ import CronInput from '../../CronInput.svelte';
3
+ import ScriptPicker from '../../ScriptPicker.svelte';
4
+ import Section from '../../Section.svelte';
5
+ import Alert from '../../common/alert/Alert.svelte';
6
+ import DrawerContent from '../../common/drawer/DrawerContent.svelte';
7
+ import Tab from '../../common/tabs/Tab.svelte';
8
+ import Tabs from '../../common/tabs/Tabs.svelte';
9
+ import { FlowService, JobService, ScheduleService, SettingService, WorkspaceService } from '../../../gen';
10
+ import { workspaceStore } from '../../../stores';
11
+ import { base } from '../../../base';
12
+ import { emptyString, formatCron, sendUserToast, tryEvery } from '../../../utils';
13
+ import SchemaForm from '../../SchemaForm.svelte';
14
+ import Button from '../../common/button/Button.svelte';
15
+ import Toggle from '../../Toggle.svelte';
16
+ import { RotateCw, Save } from 'lucide-svelte';
17
+ import { CUSTOM_TAGS_SETTING, WORKSPACE_SLACK_BOT_TOKEN_PATH } from '../../../consts';
18
+ import { loadSchemaFromPath } from '../../../infer';
19
+ import { hubPaths } from '../../../hub';
20
+ export let appPath;
21
+ export let open = false;
22
+ let appReportingEnabled = false;
23
+ let appReportingStartupDuration = 5;
24
+ let appReportingSchedule = {
25
+ cron: '0 0 12 * *',
26
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
27
+ };
28
+ let selectedTab = $enterpriseLicense
29
+ ? 'slack'
30
+ : 'custom';
31
+ let screenshotKind = 'pdf';
32
+ let customPath = undefined;
33
+ let customPathSchema = {};
34
+ let args = {};
35
+ let areArgsValid = true;
36
+ $: customPath
37
+ ? loadSchemaFromPath(customPath).then((schema) => {
38
+ customPathSchema = schema
39
+ ? {
40
+ ...schema,
41
+ properties: Object.fromEntries(Object.entries(schema.properties ?? {}).filter(([key, _]) => key !== 'screenshot' && key !== 'app_path' && key !== 'kind'))
42
+ }
43
+ : {};
44
+ })
45
+ : (customPathSchema = {});
46
+ let isSlackConnectedWorkspace = false;
47
+ async function getWorspaceSlackSetting() {
48
+ const settings = await WorkspaceService.getSettings({
49
+ workspace: $workspaceStore
50
+ });
51
+ if (settings.slack_name) {
52
+ isSlackConnectedWorkspace = true;
53
+ }
54
+ else {
55
+ isSlackConnectedWorkspace = false;
56
+ }
57
+ }
58
+ getWorspaceSlackSetting();
59
+ async function getAppReportingInfo() {
60
+ const flowPath = appPath + '_reports';
61
+ try {
62
+ const flow = await FlowService.getFlowByPath({
63
+ workspace: $workspaceStore,
64
+ path: flowPath
65
+ });
66
+ const schedule = await ScheduleService.getSchedule({
67
+ workspace: $workspaceStore,
68
+ path: flowPath
69
+ });
70
+ appReportingSchedule = {
71
+ cron: schedule.schedule,
72
+ timezone: schedule.timezone
73
+ };
74
+ appReportingStartupDuration =
75
+ schedule.args?.startup_duration ?? appReportingStartupDuration;
76
+ screenshotKind = schedule.args?.kind ?? screenshotKind;
77
+ selectedTab =
78
+ flow.value.modules[1]?.value.type === 'script'
79
+ ? flow.value.modules[1].value.path === notificationScripts.email.path
80
+ ? 'email'
81
+ : flow.value.modules[1].value.path === notificationScripts.slack.path
82
+ ? 'slack'
83
+ : flow.value.modules[1].value.path === notificationScripts.discord.path
84
+ ? 'discord'
85
+ : 'custom'
86
+ : 'custom';
87
+ const nargs = schedule.args
88
+ ? Object.fromEntries(Object.entries(schedule.args).filter(([key, _]) => key !== 'app_path' && key !== 'startup_duration' && key !== 'kind'))
89
+ : {};
90
+ setTimeout(() => {
91
+ args = structuredClone(nargs);
92
+ });
93
+ customPath =
94
+ selectedTab === 'custom' &&
95
+ flow.value.modules[1]?.value.type === 'script' &&
96
+ !flow.value.modules[1].value.path.startsWith('hub/')
97
+ ? flow.value.modules[1].value.path
98
+ : undefined;
99
+ appReportingEnabled = true;
100
+ }
101
+ catch (err) { }
102
+ }
103
+ $: appPath && getAppReportingInfo();
104
+ async function disableAppReporting() {
105
+ const flowPath = appPath + '_reports';
106
+ await ScheduleService.deleteSchedule({
107
+ workspace: $workspaceStore,
108
+ path: flowPath
109
+ });
110
+ await FlowService.deleteFlowByPath({
111
+ workspace: $workspaceStore,
112
+ path: flowPath
113
+ });
114
+ appReportingEnabled = false;
115
+ sendUserToast('App reporting disabled');
116
+ }
117
+ const appPreviewScript = `import puppeteer from 'puppeteer-core';
118
+ import dayjs from 'dayjs';
119
+ export async function main(app_path: string, startup_duration = 5, kind: 'pdf' | 'png' = 'pdf') {
120
+ let browser = null
121
+ try {
122
+ browser = await puppeteer.launch({ headless: true, executablePath: '/usr/bin/chromium', args: ['--no-sandbox',
123
+ '--no-zygote',
124
+ '--disable-setuid-sandbox',
125
+ '--disable-dev-shm-usage',
126
+ '--disable-gpu'] });
127
+ const page = await browser.newPage();
128
+ await page.setCookie({
129
+ "name": "token",
130
+ "value": Bun.env["WM_TOKEN"],
131
+ "domain": Bun.env["BASE_URL"]?.replace(/https?:\\/\\//, '')
132
+ })
133
+ page
134
+ .on('console', msg =>
135
+ console.log(dayjs().format("HH:mm:ss") + " " + msg.type().substr(0, 3).toUpperCase() + " " + msg.text()))
136
+ .on('pageerror', ({ msg }) => console.log(dayjs().format("HH:mm:ss") + " " + msg));
137
+ await page.setViewport({ width: 1200, height: 2000 });
138
+ await page.goto(Bun.env["BASE_URL"] + '/apps/get/' + app_path + '?workspace=' + Bun.env["WM_WORKSPACE"] + "&hideRefreshBar=true&hideEditBtn=true");
139
+ await page.waitForSelector("#app-content", { timeout: 20000 })
140
+ await new Promise((resolve, _) => {
141
+ setTimeout(resolve, startup_duration * 1000)
142
+ })
143
+ await page.$eval("#sidebar", el => el.remove())
144
+ await page.$eval("#content", el => el.classList.remove("md:pl-12"))
145
+ await page.$$eval(".app-component-refresh-btn", els => els.forEach(el => el.remove()))
146
+ await page.$$eval(".app-table-footer-btn", els => els.forEach(el => el.remove()))
147
+ const elem = await page.$('#app-content');
148
+ const { height } = await elem.boundingBox();
149
+ await page.setViewport({ width: 1200, height });
150
+ await new Promise((resolve, _) => {
151
+ setTimeout(resolve, 500)
152
+ })
153
+ const screenshot = kind === "pdf" ? await page.pdf({
154
+ printBackground: true,
155
+ width: 1200,
156
+ height
157
+ }) : await page.screenshot({
158
+ fullPage: true,
159
+ type: "png",
160
+ captureBeyondViewport: false
161
+ });
162
+ await browser.close();
163
+ return Buffer.from(screenshot).toString('base64');
164
+ } catch (err) {
165
+ if (browser) {
166
+ await browser.close();
167
+ }
168
+ throw err;
169
+ }
170
+ }`;
171
+ const notificationScripts = {
172
+ discord: {
173
+ path: hubPaths.discordReport,
174
+ schema: {
175
+ type: 'object',
176
+ properties: {
177
+ discord_webhook: {
178
+ type: 'object',
179
+ format: 'resource-discord_webhook',
180
+ properties: {},
181
+ required: [],
182
+ description: ''
183
+ }
184
+ },
185
+ required: ['discord_webhook']
186
+ }
187
+ },
188
+ slack: {
189
+ path: hubPaths.slackReport,
190
+ schema: {
191
+ type: 'object',
192
+ properties: {
193
+ channel: {
194
+ type: 'string',
195
+ default: ''
196
+ }
197
+ },
198
+ required: ['channel']
199
+ }
200
+ },
201
+ email: {
202
+ path: hubPaths.smtpReport,
203
+ schema: {
204
+ type: 'object',
205
+ properties: {
206
+ smtp: {
207
+ type: 'object',
208
+ format: 'resource-smtp',
209
+ properties: {},
210
+ required: [],
211
+ description: ''
212
+ },
213
+ from_email: {
214
+ type: 'string',
215
+ default: ''
216
+ },
217
+ to_email: {
218
+ type: 'string',
219
+ default: ''
220
+ }
221
+ },
222
+ required: ['smtp', 'from_email', 'to_email']
223
+ }
224
+ }
225
+ };
226
+ function getFlowArgs() {
227
+ return {
228
+ app_path: appPath,
229
+ startup_duration: appReportingStartupDuration,
230
+ kind: screenshotKind,
231
+ ...args,
232
+ ...(selectedTab === 'slack'
233
+ ? {
234
+ slack: '$res:' + WORKSPACE_SLACK_BOT_TOKEN_PATH
235
+ }
236
+ : {})
237
+ };
238
+ }
239
+ function getFlowValue() {
240
+ const notifInputTransforms = {
241
+ app_path: {
242
+ type: 'javascript',
243
+ expr: 'flow_input.app_path'
244
+ },
245
+ screenshot: {
246
+ type: 'javascript',
247
+ expr: 'results.a'
248
+ },
249
+ kind: {
250
+ type: 'javascript',
251
+ expr: 'flow_input.kind'
252
+ },
253
+ ...Object.fromEntries(Object.keys(args).map((key) => [
254
+ key,
255
+ {
256
+ type: 'javascript',
257
+ expr: `flow_input.${key}`
258
+ }
259
+ ])),
260
+ ...(selectedTab === 'slack'
261
+ ? {
262
+ slack: {
263
+ type: 'javascript',
264
+ expr: 'flow_input.slack'
265
+ }
266
+ }
267
+ : {})
268
+ };
269
+ const value = {
270
+ modules: [
271
+ {
272
+ id: 'a',
273
+ value: {
274
+ type: 'rawscript',
275
+ tag: 'chromium',
276
+ content: appPreviewScript,
277
+ language: 'bun',
278
+ input_transforms: {
279
+ app_path: {
280
+ expr: 'flow_input.app_path',
281
+ type: 'javascript'
282
+ },
283
+ startup_duration: {
284
+ expr: 'flow_input.startup_duration',
285
+ type: 'javascript'
286
+ },
287
+ kind: {
288
+ expr: 'flow_input.kind',
289
+ type: 'javascript'
290
+ }
291
+ }
292
+ }
293
+ },
294
+ {
295
+ id: 'b',
296
+ value: {
297
+ type: 'script',
298
+ path: selectedTab === 'custom' ? customPath || '' : notificationScripts[selectedTab].path,
299
+ input_transforms: notifInputTransforms
300
+ }
301
+ }
302
+ ]
303
+ };
304
+ return value;
305
+ }
306
+ async function enableAppReporting() {
307
+ const flowPath = appPath + '_reports';
308
+ try {
309
+ // will only work if the user is super admin
310
+ const customTags = ((await SettingService.getGlobal({
311
+ key: CUSTOM_TAGS_SETTING
312
+ })) ?? []);
313
+ if (!customTags.includes('chromium')) {
314
+ await SettingService.setGlobal({
315
+ key: CUSTOM_TAGS_SETTING,
316
+ requestBody: {
317
+ value: [...customTags, 'chromium']
318
+ }
319
+ });
320
+ }
321
+ }
322
+ catch (err) { }
323
+ await FlowService.deleteFlowByPath({
324
+ workspace: $workspaceStore,
325
+ path: flowPath
326
+ });
327
+ await FlowService.createFlow({
328
+ workspace: $workspaceStore,
329
+ requestBody: {
330
+ summary: appPath + ' - Reports flow',
331
+ value: getFlowValue(),
332
+ schema: {
333
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
334
+ properties: {
335
+ app_path: {
336
+ description: '',
337
+ type: 'string',
338
+ default: null,
339
+ format: ''
340
+ },
341
+ startup_duration: {
342
+ description: '',
343
+ type: 'integer',
344
+ default: 5,
345
+ format: ''
346
+ },
347
+ kind: {
348
+ description: '',
349
+ type: 'string',
350
+ enum: ['pdf', 'png'],
351
+ default: 'pdf',
352
+ format: ''
353
+ },
354
+ ...(selectedTab === 'custom'
355
+ ? customPathSchema.properties
356
+ : notificationScripts[selectedTab].schema.properties),
357
+ ...(selectedTab === 'slack'
358
+ ? {
359
+ slack: {
360
+ description: '',
361
+ type: 'object',
362
+ format: 'resource-slack',
363
+ properties: {},
364
+ required: []
365
+ }
366
+ }
367
+ : {})
368
+ },
369
+ required: [
370
+ 'app_path',
371
+ 'startup_duration',
372
+ 'kind',
373
+ ...(selectedTab === 'custom'
374
+ ? customPathSchema.required
375
+ : notificationScripts[selectedTab].schema.required),
376
+ ...(selectedTab === 'slack' ? ['slack'] : [])
377
+ ],
378
+ type: 'object'
379
+ },
380
+ path: flowPath
381
+ }
382
+ });
383
+ try {
384
+ await ScheduleService.deleteSchedule({
385
+ workspace: $workspaceStore,
386
+ path: flowPath
387
+ });
388
+ }
389
+ catch (err) { }
390
+ await ScheduleService.createSchedule({
391
+ workspace: $workspaceStore,
392
+ requestBody: {
393
+ path: flowPath,
394
+ schedule: formatCron(appReportingSchedule.cron),
395
+ timezone: appReportingSchedule.timezone,
396
+ script_path: flowPath,
397
+ is_flow: true,
398
+ args: getFlowArgs(),
399
+ enabled: true
400
+ }
401
+ });
402
+ appReportingEnabled = true;
403
+ }
404
+ let testLoading = false;
405
+ async function testReport() {
406
+ try {
407
+ testLoading = true;
408
+ const jobId = await JobService.runFlowPreview({
409
+ workspace: $workspaceStore,
410
+ requestBody: {
411
+ args: getFlowArgs(),
412
+ value: getFlowValue()
413
+ }
414
+ });
415
+ tryEvery({
416
+ tryCode: async () => {
417
+ let testResult = await JobService.getCompletedJob({
418
+ workspace: $workspaceStore,
419
+ id: jobId
420
+ });
421
+ testLoading = false;
422
+ sendUserToast(testResult.success
423
+ ? 'Report sent successfully'
424
+ : 'Report error: ' + testResult.result?.['error']?.['message'], !testResult.success);
425
+ },
426
+ timeoutCode: async () => {
427
+ testLoading = false;
428
+ sendUserToast('Reports flow did not return after 30s', true);
429
+ try {
430
+ await JobService.cancelQueuedJob({
431
+ workspace: $workspaceStore,
432
+ id: jobId,
433
+ requestBody: {
434
+ reason: 'Reports flow did not return after 30s'
435
+ }
436
+ });
437
+ }
438
+ catch (err) {
439
+ console.error(err);
440
+ }
441
+ },
442
+ interval: 500,
443
+ timeout: 30000
444
+ });
445
+ }
446
+ catch (err) {
447
+ sendUserToast('Could not test reports flow: ' + err, true);
448
+ testLoading = false;
449
+ }
450
+ }
451
+ let disabled = true;
452
+ $: disabled =
453
+ emptyString(appReportingSchedule.cron) ||
454
+ (selectedTab === 'custom' && emptyString(customPath)) ||
455
+ (selectedTab === 'slack' && !isSlackConnectedWorkspace) ||
456
+ !areArgsValid;
457
+ </script>
458
+
459
+ <DrawerContent
460
+ on:close={() => (open = false)}
461
+ title="Schedule Reports"
462
+ tooltip="Send a PDF or PNG preview of any app at a given schedule"
463
+ documentationLink="https://www.windmill.dev/docs/apps/schedule_reports"
464
+ ><svelte:fragment slot="actions">
465
+ <div class="mr-4 center-center">
466
+ <Toggle
467
+ checked={appReportingEnabled}
468
+ options={{ right: 'enable', left: 'disable' }}
469
+ on:change={async () => {
470
+ if (appReportingEnabled) {
471
+ disableAppReporting()
472
+ } else {
473
+ await enableAppReporting()
474
+ sendUserToast('App reporting enabled')
475
+ }
476
+ }}
477
+ disabled={disabled && !appReportingEnabled}
478
+ />
479
+ </div>
480
+ <Button
481
+ color="dark"
482
+ startIcon={{ icon: Save }}
483
+ size="sm"
484
+ on:click={async () => {
485
+ await enableAppReporting()
486
+ sendUserToast('App reporting updated')
487
+ open = false
488
+ }}
489
+ {disabled}
490
+ >
491
+ {appReportingEnabled ? 'Update' : 'Save and enable'}
492
+ </Button>
493
+ </svelte:fragment>
494
+ <div class="flex flex-col gap-8">
495
+ <Alert type="info" title="Scheduled PDF/PNG reports"
496
+ >Send a PDF or PNG preview of the app at a given schedule. Enabling this feature will create a
497
+ flow and a schedule in your workspace.
498
+ <br /><br />
499
+ For the flow to be executed, you need to set the WORKER_GROUP environment variable of one of your
500
+ workers to "reports" or add the tag "chromium" to one of your worker groups.
501
+ </Alert>
502
+
503
+ <Section label="Reporting schedule">
504
+ <CronInput
505
+ bind:schedule={appReportingSchedule.cron}
506
+ bind:timezone={appReportingSchedule.timezone}
507
+ />
508
+ </Section>
509
+
510
+ <Section
511
+ label="Startup duration in seconds"
512
+ tooltip="The number of seconds to wait before capturing a preview to ensure that all startup scripts
513
+ have been executed."
514
+ >
515
+ <div class="w-full pt-2">
516
+ <input
517
+ type="number"
518
+ class="text-sm w-full font-semibold"
519
+ bind:value={appReportingStartupDuration}
520
+ />
521
+ </div>
522
+ </Section>
523
+
524
+ <Section label="Screenshot kind">
525
+ <div class="w-full pt-2">
526
+ <select class="text-sm w-full font-semibold" bind:value={screenshotKind}>
527
+ <option value="pdf">PDF</option>
528
+ <option value="png">PNG</option>
529
+ </select>
530
+ </div></Section
531
+ >
532
+
533
+ <Section label="Notification">
534
+ <Tabs bind:selected={selectedTab}>
535
+ {#if !$enterpriseLicense}
536
+ <Tab value="custom">Custom</Tab>
537
+ {/if}
538
+ <Tab value="slack" disabled={!$enterpriseLicense}
539
+ >Slack{!$enterpriseLicense ? ' (EE only)' : ''}</Tab
540
+ >
541
+ <Tab value="discord" disabled={!$enterpriseLicense}
542
+ >Discord{!$enterpriseLicense ? ' (EE only)' : ''}</Tab
543
+ >
544
+ <Tab value="email" disabled={!$enterpriseLicense}>
545
+ <div class="flex flex-row gap-1 items-center"
546
+ >Email{!$enterpriseLicense ? ' (EE only)' : ''}
547
+ </div>
548
+ </Tab>
549
+ {#if $enterpriseLicense}
550
+ <Tab value="custom">Custom</Tab>
551
+ {/if}
552
+ </Tabs>
553
+ {#if selectedTab === 'custom'}
554
+ <div class="pt-2">
555
+ <ScriptPicker
556
+ on:select={(ev) => {
557
+ customPath = ev.detail.path
558
+ }}
559
+ initialPath={customPath}
560
+ allowRefresh
561
+ />
562
+ </div>
563
+ <div class="prose text-2xs text-tertiary mt-2">
564
+ Pick a script that does whatever with the PDF/PNG report.
565
+
566
+ <br />
567
+
568
+ The script chosen is passed the parameters `screenshot: string`, `kind: 'pdf' | 'png'`,
569
+ `app_path: string` where `screenshot` is the base64 encoded PDF/PNG report, `kind` is the
570
+ type of the screenshot, and `app_path` is the path of the app being reported.
571
+ </div>
572
+ {/if}
573
+ {#if selectedTab === 'slack'}
574
+ <div class="pt-4">
575
+ {#if isSlackConnectedWorkspace}
576
+ <Alert type="info" title="Will use the Slack resource linked to the workspace" />
577
+ {:else}
578
+ <Alert type="error" title="Workspace not connected to Slack">
579
+ <div class="flex flex-row gap-x-1 w-full items-center">
580
+ <p class="text-clip grow min-w-0">
581
+ The workspace needs to be connected to Slack to use this feature. You can <a
582
+ target="_blank"
583
+ href="{base}/workspace_settings?tab=slack">configure it here</a
584
+ >.
585
+ </p>
586
+ <Button
587
+ variant="border"
588
+ color="light"
589
+ on:click={getWorspaceSlackSetting}
590
+ startIcon={{ icon: RotateCw }}
591
+ />
592
+ </div>
593
+ </Alert>
594
+ {/if}
595
+ </div>
596
+ {/if}
597
+ <div class="w-full pt-4">
598
+ {#if selectedTab !== 'custom' || customPath !== undefined}
599
+ {#key selectedTab + JSON.stringify(customPathSchema ?? {})}
600
+ <SchemaForm
601
+ bind:isValid={areArgsValid}
602
+ bind:args
603
+ schema={selectedTab !== 'custom'
604
+ ? notificationScripts[selectedTab].schema
605
+ : customPathSchema}
606
+ />
607
+ {/key}
608
+ {/if}
609
+ </div>
610
+ <Button
611
+ loading={testLoading}
612
+ {disabled}
613
+ on:click={testReport}
614
+ size="xs"
615
+ color="dark"
616
+ btnClasses="w-auto"
617
+ >
618
+ Send test report
619
+ </Button>
620
+ </Section>
621
+ </div>
622
+ </DrawerContent>
@@ -0,0 +1,17 @@
1
+ import { SvelteComponent } from "svelte";
2
+ declare const __propDef: {
3
+ props: {
4
+ appPath: string;
5
+ open?: boolean | undefined;
6
+ };
7
+ events: {
8
+ [evt: string]: CustomEvent<any>;
9
+ };
10
+ slots: {};
11
+ };
12
+ export type AppReportsDrawerInnerProps = typeof __propDef.props;
13
+ export type AppReportsDrawerInnerEvents = typeof __propDef.events;
14
+ export type AppReportsDrawerInnerSlots = typeof __propDef.slots;
15
+ export default class AppReportsDrawerInner extends SvelteComponent<AppReportsDrawerInnerProps, AppReportsDrawerInnerEvents, AppReportsDrawerInnerSlots> {
16
+ }
17
+ export {};