@peers-app/peers-ui 0.13.6 → 0.14.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 (84) hide show
  1. package/dist/components/left-bar.js +0 -9
  2. package/dist/components/router.js +0 -44
  3. package/dist/index.d.ts +1 -1
  4. package/dist/index.js +1 -1
  5. package/dist/mention-configs.d.ts +0 -2
  6. package/dist/mention-configs.js +1 -38
  7. package/dist/screens/search/global-search.js +2 -4
  8. package/dist/screens/workflows/workflow-details.js +5 -56
  9. package/dist/system-apps/index.d.ts +0 -4
  10. package/dist/system-apps/index.js +1 -18
  11. package/dist/ui-defaults/index.d.ts +0 -1
  12. package/dist/ui-defaults/index.js +0 -1
  13. package/dist/ui-defaults/list-screen.js +0 -1
  14. package/docs/tabs-ui.md +6 -21
  15. package/package.json +3 -3
  16. package/src/components/left-bar.tsx +0 -12
  17. package/src/components/router.tsx +0 -48
  18. package/src/index.tsx +2 -2
  19. package/src/mention-configs.ts +1 -40
  20. package/src/screens/search/global-search.tsx +2 -6
  21. package/src/screens/workflows/workflow-details.tsx +3 -28
  22. package/src/system-apps/index.ts +0 -14
  23. package/src/ui-defaults/index.ts +0 -1
  24. package/src/ui-defaults/list-screen.tsx +0 -1
  25. package/dist/screens/events/cron.d.ts +0 -3
  26. package/dist/screens/events/cron.js +0 -77
  27. package/dist/screens/events/event-details.d.ts +0 -6
  28. package/dist/screens/events/event-details.js +0 -112
  29. package/dist/screens/events/event-handlers.d.ts +0 -7
  30. package/dist/screens/events/event-handlers.js +0 -84
  31. package/dist/screens/events/event-info.d.ts +0 -5
  32. package/dist/screens/events/event-info.js +0 -19
  33. package/dist/screens/events/event-list.d.ts +0 -2
  34. package/dist/screens/events/event-list.js +0 -107
  35. package/dist/screens/events/event-schedule.d.ts +0 -5
  36. package/dist/screens/events/event-schedule.js +0 -124
  37. package/dist/screens/knowledge/knowledge-frame-details.bk.d.ts +0 -6
  38. package/dist/screens/knowledge/knowledge-frame-details.bk.js +0 -84
  39. package/dist/screens/knowledge/knowledge-frame-details.d.ts +0 -8
  40. package/dist/screens/knowledge/knowledge-frame-details.js +0 -143
  41. package/dist/screens/knowledge/knowledge-frame-list.d.ts +0 -2
  42. package/dist/screens/knowledge/knowledge-frame-list.js +0 -45
  43. package/dist/screens/knowledge/knowledge-value-details.d.ts +0 -6
  44. package/dist/screens/knowledge/knowledge-value-details.js +0 -150
  45. package/dist/screens/knowledge/knowledge-value-list-item.d.ts +0 -5
  46. package/dist/screens/knowledge/knowledge-value-list-item.js +0 -39
  47. package/dist/screens/knowledge/knowledge-value-list.d.ts +0 -3
  48. package/dist/screens/knowledge/knowledge-value-list.js +0 -123
  49. package/dist/screens/predicates/predicate-details.d.ts +0 -6
  50. package/dist/screens/predicates/predicate-details.js +0 -103
  51. package/dist/screens/predicates/predicate-list.d.ts +0 -2
  52. package/dist/screens/predicates/predicate-list.js +0 -46
  53. package/dist/screens/workflows/workflow-subscriptions.d.ts +0 -6
  54. package/dist/screens/workflows/workflow-subscriptions.js +0 -81
  55. package/dist/system-apps/events.app.d.ts +0 -2
  56. package/dist/system-apps/events.app.js +0 -8
  57. package/dist/system-apps/knowledge-frames.app.d.ts +0 -2
  58. package/dist/system-apps/knowledge-frames.app.js +0 -9
  59. package/dist/system-apps/knowledge-values.app.d.ts +0 -2
  60. package/dist/system-apps/knowledge-values.app.js +0 -9
  61. package/dist/system-apps/predicates.app.d.ts +0 -2
  62. package/dist/system-apps/predicates.app.js +0 -8
  63. package/dist/ui-defaults/notes-editor.d.ts +0 -7
  64. package/dist/ui-defaults/notes-editor.js +0 -41
  65. package/src/screens/events/cron.ts +0 -74
  66. package/src/screens/events/event-details.tsx +0 -117
  67. package/src/screens/events/event-handlers.tsx +0 -61
  68. package/src/screens/events/event-info.tsx +0 -29
  69. package/src/screens/events/event-list.tsx +0 -104
  70. package/src/screens/events/event-schedule.tsx +0 -130
  71. package/src/screens/knowledge/knowledge-frame-details.bk.tsx +0 -160
  72. package/src/screens/knowledge/knowledge-frame-details.tsx +0 -176
  73. package/src/screens/knowledge/knowledge-frame-list.tsx +0 -49
  74. package/src/screens/knowledge/knowledge-value-details.tsx +0 -181
  75. package/src/screens/knowledge/knowledge-value-list-item.tsx +0 -48
  76. package/src/screens/knowledge/knowledge-value-list.tsx +0 -131
  77. package/src/screens/predicates/predicate-details.tsx +0 -125
  78. package/src/screens/predicates/predicate-list.tsx +0 -50
  79. package/src/screens/workflows/workflow-subscriptions.tsx +0 -58
  80. package/src/system-apps/events.app.ts +0 -7
  81. package/src/system-apps/knowledge-frames.app.ts +0 -8
  82. package/src/system-apps/knowledge-values.app.ts +0 -8
  83. package/src/system-apps/predicates.app.ts +0 -7
  84. package/src/ui-defaults/notes-editor.tsx +0 -51
@@ -1,41 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.FullScreenMarkdownEditor = void 0;
7
- const peers_sdk_1 = require("@peers-app/peers-sdk");
8
- const react_1 = __importDefault(require("react"));
9
- const zod_1 = require("zod");
10
- const editor_inline_1 = require("../components/markdown-editor/editor-inline");
11
- const ui_loader_1 = require("../ui-router/ui-loader");
12
- const FullScreenMarkdownEditor = (props) => {
13
- return (react_1.default.createElement(editor_inline_1.MarkdownEditorInline, { value: props.markdown, maxHeight: 'calc(100vh - 160px)', autoFocus: true }));
14
- };
15
- exports.FullScreenMarkdownEditor = FullScreenMarkdownEditor;
16
- (0, ui_loader_1.registerInternalPeersUI)({
17
- peersUIId: '00m4rof6uwka5kfi6t7rav8t3',
18
- component: (props) => {
19
- const doc = props.knowledgeValue;
20
- const markdown = (0, peers_sdk_1.computed)({
21
- read: () => doc.value?.body || '',
22
- write: (value) => {
23
- doc.value.body = value;
24
- doc.qs.value.notifySubscribers();
25
- doc.q(doc.q() + 1);
26
- }
27
- });
28
- return (react_1.default.createElement(exports.FullScreenMarkdownEditor, { key: doc.knowledgeValueId, markdown: markdown }));
29
- },
30
- propsSchema: zod_1.z.object({
31
- knowledgeValue: peers_sdk_1.knowledgeValueSchema, // TODO fix this
32
- }),
33
- routes: [
34
- {
35
- // KnowledgeValue with PeerType: Note
36
- isMatch: (props, context) => props.knowledgeValue?.peerTypeId === '00m3g0ntcop3mrh6ynuzgekiy',
37
- uiEditMode: 'edit',
38
- uiCategory: 'details',
39
- }
40
- ]
41
- });
@@ -1,74 +0,0 @@
1
- import cronValidate from "cron-validate";
2
- import moment from "moment-timezone";
3
- import { parseExpression } from 'cron-parser';
4
-
5
-
6
- export function getCronErrors(cronExpression: string): string | false {
7
- const validationResult = cronValidate(cronExpression);
8
-
9
- if (validationResult.isError()) {
10
- const errors = validationResult.getError();
11
- const errorMarkdown = ['Validation errors:', ...errors].join('\n- ');
12
- return errorMarkdown;
13
- }
14
-
15
- let parseError = '';
16
- try {
17
- parseExpression(cronExpression);
18
- } catch (e: any) {
19
- parseError = e.message;
20
- }
21
- if (parseError) {
22
- return 'Validation error: ' + parseError;
23
- }
24
- return false;
25
- }
26
-
27
- export function getCronExplanation(cronExpression: string) {
28
- if (!cronExpression) {
29
- return '';
30
- }
31
- function formatDate(date: Date) {
32
- // let dtStr = moment
33
- return moment(date).calendar(null, {
34
- sameDay: '[Today at] LT',
35
- nextDay: '[Tomorrow at] LT',
36
- nextWeek: 'dddd [at] LT',
37
- lastDay: '[Yesterday at] LT',
38
- lastWeek: '[Last] dddd [at] LT',
39
- sameElse: 'L [at] LT'
40
- }) + `\n - \`${date.toISOString().replace(':00.000Z', 'Z')}\``;
41
- }
42
- let parsed = parseExpression(cronExpression);
43
-
44
- const strDates: string[] = [];
45
- let i = 1;
46
- while (true) {
47
- const dt = parsed.prev().toString();
48
- strDates.push(`- ${formatDate(new Date(dt))}`);
49
- i++;
50
- if (i > 3) break;
51
- }
52
- strDates.push('Prior three dates:');
53
- strDates.reverse();
54
- strDates.push('\nNext three dates:');
55
- i = 1;
56
- parsed = parseExpression(cronExpression);
57
- while (true) {
58
- const dt = parsed.next().toString();
59
- strDates.push(`- ${formatDate(new Date(dt))}`);
60
- i++;
61
- if (i > 3) break;
62
- }
63
-
64
- return strDates.join('\n');
65
- }
66
-
67
- export function getNextCronDate(cronExpression: string): Date {
68
- const errors = getCronErrors(cronExpression);
69
- if (errors) {
70
- throw new Error(errors);
71
- }
72
- const parsed = parseExpression(cronExpression);
73
- return new Date(parsed.next().toString());
74
- }
@@ -1,117 +0,0 @@
1
- import { IPeerEventHandler, observable, PeerEventHandlers, PeerEventTypes } from "@peers-app/peers-sdk";
2
- import React, { useState } from "react";
3
- import { Input } from "../../components/input";
4
- import { IOSchemaEditor } from "../../components/io-schema";
5
- import { LoadingIndicator } from "../../components/loading-indicator";
6
- import { SaveButton } from "../../components/save-button";
7
- import { ScreenTabBody, Tabs } from "../../components/tabs";
8
- import { usePromise } from "../../hooks";
9
- import { updateActiveTabTitle } from "../../tabs-layout/tabs-state";
10
- import { PeerEventHandlersUI } from "./event-handlers";
11
- import { PeerEventInfo } from "./event-info";
12
- import { PeerEventSchedule } from "./event-schedule";
13
-
14
- interface IProps {
15
- peerEventTypeId: string;
16
- }
17
-
18
- export const PeerEventDetails = (props: IProps) => {
19
-
20
- const peerEventType = usePromise(async () => {
21
- const peerEvent = await PeerEventTypes().get(props.peerEventTypeId);
22
- if (!peerEvent) {
23
- throw new Error('Workflow not found');
24
- }
25
- const doc = PeerEventTypes().initDoc(peerEvent);
26
- updateActiveTabTitle(doc.name || "Event");
27
- return doc;
28
- }, undefined, [props.peerEventTypeId]);
29
-
30
- const [handlers] = useState(() => observable([] as IPeerEventHandler[]));
31
-
32
- const handlersLoaded = usePromise(async () => {
33
- if (!peerEventType) return false;
34
- const _handlers = await PeerEventHandlers().list({ peerEventTypeId: peerEventType?.peerEventTypeId });
35
- handlers(_handlers);
36
- return true;
37
- }, false, [peerEventType]);
38
-
39
- const allLoaded = !!(peerEventType && handlersLoaded);
40
-
41
- if (!allLoaded) {
42
- return <LoadingIndicator />;
43
- }
44
-
45
- async function saveChanges() {
46
- if (!peerEventType) return;
47
- await peerEventType.save();
48
- const oldHandlers = await PeerEventHandlers().list({ peerEventTypeId: peerEventType.peerEventTypeId });
49
- for (const oldHandler of oldHandlers) {
50
- await PeerEventHandlers().delete(oldHandler.peerEventHandlerId);
51
- }
52
- for (const handler of handlers()) {
53
- PeerEventHandlers().save(handler, { restoreIfDeleted: true });
54
- }
55
- }
56
-
57
- return (
58
- <div className="container-fluid p-3">
59
-
60
- <div className="d-flex">
61
- <div>
62
- <h4>
63
- <i className="bi bi-lightning-charge-fill me-2"></i>
64
- </h4>
65
- </div>
66
- <div className="flex-grow-1">
67
- <h4>
68
- <Input
69
- key={peerEventType.peerEventTypeId}
70
- className='border border-0'
71
- style={{ width: '100%', outline: 'none', backgroundColor: 'transparent' }}
72
- value={peerEventType.qs.name}
73
- />
74
- </h4>
75
- </div>
76
- <div>
77
- <SaveButton
78
- key={peerEventType.peerEventTypeId}
79
- onClick={saveChanges}
80
- doc={peerEventType}
81
- />
82
- </div>
83
- </div>
84
-
85
- <Tabs
86
- key={peerEventType.peerEventTypeId}
87
- tabs={[
88
- {
89
- name: 'Info', content:
90
- <ScreenTabBody>
91
- <PeerEventInfo peerEventType={peerEventType} />
92
- </ScreenTabBody>
93
- },
94
- {
95
- name: 'Schema', content:
96
- <ScreenTabBody>
97
- <IOSchemaEditor ioSchema={peerEventType.qs.schema} simpleValueName="Event" />
98
- </ScreenTabBody>
99
- },
100
- {
101
- name: 'Triggers', content:
102
- <ScreenTabBody>
103
- <PeerEventSchedule peerEventType={peerEventType} />
104
- </ScreenTabBody>
105
- },
106
- {
107
- name: 'Handlers', content:
108
- <ScreenTabBody>
109
- <PeerEventHandlersUI peerEventType={peerEventType} handlers={handlers} />
110
- </ScreenTabBody>
111
- },
112
-
113
- ]}
114
- />
115
- </div>
116
- )
117
- }
@@ -1,61 +0,0 @@
1
- import { observable, Observable } from "@peers-app/peers-sdk";
2
- import { isEqual } from "lodash";
3
- import React, { useState } from "react";
4
- import { newid, IDoc, IPeerEventHandler, IPeerEventType, Workflows } from "@peers-app/peers-sdk";
5
- import { Tooltip } from "../../components/tooltip";
6
- import { MarkdownEditorInline } from "../../components/markdown-editor/editor-inline";
7
- import { LoadingIndicator } from "../../components/loading-indicator";
8
- import { formatMention, getAllMentions } from "@peers-app/peers-sdk";
9
- import { usePromise, useSubscription } from "../../hooks";
10
-
11
- export const PeerEventHandlersUI = (props: { peerEventType: IDoc<IPeerEventType>, handlers: Observable<IPeerEventHandler[]> }) => {
12
- const { peerEventType, handlers } = props;
13
-
14
- const [handlersMarkdown] = useState(() => observable(''));
15
-
16
- const markdownInitialized = usePromise(async () => {
17
- const workflowIds = handlers().map(h => h.handlerWorkflowId);
18
- const handlerWorkflows = await Workflows().list({ workflowId: { $in: workflowIds } });
19
- const workflowTitles = handlerWorkflows.reduce((acc, wf) => ({ ...acc, [wf.workflowId]: wf.name }), {} as Record<string, string>);
20
- const mentions = workflowIds.map(workflowId => '- ' + formatMention({ kind: 'workflow', id: workflowId, name: workflowTitles[workflowId] ?? workflowId }));
21
- const markdown = `${mentions.join('\n') || '- '}`;
22
- handlersMarkdown(markdown);
23
- return true;
24
- });
25
-
26
- useSubscription(handlersMarkdown, () => {
27
- if (!markdownInitialized) return;
28
- const startWorkflowIds = handlers().map(h => h.handlerWorkflowId);
29
- const workflowIds = getAllMentions(handlersMarkdown()).filter(m => m.kind === 'workflow').map(m => m.id);
30
- if (isEqual(startWorkflowIds, workflowIds)) return;
31
- const newHandlers: IPeerEventHandler[] = workflowIds.map(workflowId => ({
32
- peerEventHandlerId: newid(),
33
- peerEventTypeId: peerEventType.peerEventTypeId,
34
- handlerWorkflowId: workflowId,
35
- }));
36
- handlers(newHandlers);
37
- peerEventType.q(peerEventType.q() + 1);
38
- console.log('new handlers', newHandlers.map(h => h.handlerWorkflowId));
39
- });
40
-
41
- if (!markdownInitialized) {
42
- return <LoadingIndicator />;
43
- }
44
-
45
- return (
46
- <div>
47
-
48
- <div className='mt-2'>
49
- <small>Mention workflows this event should trigger:</small>
50
- <small>
51
- <Tooltip markdownContent={`The mentions will be reformatted as a bulleted list regardless of how they are entered. All other content except for workflow mentions will be discarded.`} />
52
- </small>
53
-
54
- <MarkdownEditorInline
55
- value={handlersMarkdown}
56
- />
57
- </div>
58
-
59
- </div>
60
- );
61
- };
@@ -1,29 +0,0 @@
1
- import React from "react";
2
- import { IDoc, IPeerEventType } from "@peers-app/peers-sdk";
3
- import { MarkdownEditorInline } from "../../components/markdown-editor/editor-inline";
4
- import { Input } from "../../components/input";
5
-
6
- export const PeerEventInfo = (props: { peerEventType: IDoc<IPeerEventType> }) => {
7
- const { peerEventType } = props;
8
-
9
- return (
10
- <div>
11
-
12
- <small>Name:</small>
13
- <Input
14
- value={peerEventType.qs.name}
15
- className="form-control mb-3 p-0 ps-2"
16
- placeholder="Event name"
17
- title="Event name"
18
- />
19
-
20
- <div className='mt-2'>
21
- <small>Description:</small>
22
- <MarkdownEditorInline
23
- value={peerEventType.qs.description as any}
24
- />
25
- </div>
26
-
27
- </div>
28
- );
29
- };
@@ -1,104 +0,0 @@
1
- import { ICursorIterable, IOSchemaType, IPeerEventType, newid, observable, PeerEventTypes } from "@peers-app/peers-sdk";
2
- import React, { useEffect, useState } from 'react';
3
- import { Input } from "../../components/input";
4
- import { LazyList } from "../../components/lazy-list";
5
- import { LoadingIndicator } from '../../components/loading-indicator';
6
- import { MarkdownWithMentions } from '../../components/markdown-with-mentions';
7
- import { isDesktop, mainContentPath } from '../../globals';
8
- import { useObservable } from "../../hooks";
9
-
10
- export function PeerEventList() {
11
- const [searchTextObs] = useState(() => observable(''));
12
- const [searchText] = useObservable(searchTextObs);
13
-
14
- const [cursorObs] = useState(() => observable<ICursorIterable<IPeerEventType> | undefined>());
15
- const [cursorId] = useState(() => observable(newid()));
16
-
17
- async function newCursor() {
18
- const cursor = await PeerEventTypes().cursor({ name: { $matchWords: searchText } }, { sortBy: ['-createdAt'] });
19
- cursorObs(cursor);
20
- cursorId(newid());
21
- return cursor;
22
- }
23
-
24
- useEffect(() => {
25
- newCursor();
26
- }, [searchText]);
27
-
28
- async function searchSubmit(evt: React.KeyboardEvent<HTMLInputElement>) {
29
- if (evt.key !== "Enter") return;
30
- if (!searchText.trim()) return;
31
- const peerEventName = searchText.trim();
32
- const event = await PeerEventTypes().initRecord({
33
- name: peerEventName,
34
- description: '',
35
- schema: {
36
- type: IOSchemaType.none,
37
- fields: []
38
- }
39
- });
40
- await PeerEventTypes().insert(event);
41
- mainContentPath(`events/${event.peerEventTypeId}`);
42
- }
43
-
44
- async function loadMore(events: IPeerEventType[]): Promise<IPeerEventType[]> {
45
- let moreMatches: IPeerEventType[] = [];
46
- let cursor = cursorObs() || await newCursor();
47
- for await (const event of cursor) {
48
- if (events.find(e => e.peerEventTypeId === event.peerEventTypeId)) continue;
49
- moreMatches.push(event);
50
- if (searchText.length && moreMatches.length > 5) break;
51
- if (moreMatches.length >= 50) break;
52
- }
53
- if (moreMatches.length === 0) {
54
- cursorObs(undefined);
55
- }
56
- return moreMatches;
57
- }
58
-
59
- return (
60
- <div className='container-fluid'>
61
- <Input value={searchTextObs} className="form-control mt-3" style={{ marginBottom: "10px" }} placeholder="Search or create new event"
62
- autoFocus={isDesktop() ? true : false}
63
- onKeyUp={evt => searchSubmit(evt)}
64
- />
65
-
66
- <div className="peers-list-container">
67
- <LazyList
68
- key={cursorId()}
69
- loadMore={loadMore}
70
- scrollThreshold={0.6}
71
- renderItems={(events) => {
72
- return events.map(event => {
73
- return (
74
- <div
75
- key={event.peerEventTypeId}
76
- className='container-fluid pb-4'
77
- >
78
- <i className="bi bi-lightning-charge-fill"></i>&nbsp;
79
- <a href={`#events/${event.peerEventTypeId}`}>
80
- {event.name}
81
- </a>
82
- <div style={{ paddingLeft: '20px' }}>
83
- <MarkdownWithMentions content={event.description} />
84
- </div>
85
-
86
- </div>
87
- )
88
- })
89
- }}
90
- loadingIndicator={
91
- <div className="d-flex justify-content-center" style={{ height: 200 }}>
92
- <LoadingIndicator />
93
- </div>
94
- }
95
- endOfList={
96
- <div className="d-flex justify-content-center" style={{ height: 200 }}>
97
- {/* <span className="h3">End of List</span> */}
98
- </div>
99
- }
100
- />
101
- </div>
102
- </div>
103
- );
104
- }
@@ -1,130 +0,0 @@
1
- import { IDoc, IPeerEventType, Observable, } from "@peers-app/peers-sdk";
2
- import React, { useEffect } from "react";
3
- import { Input } from "../../components/input";
4
- import { MarkdownWithMentions } from "../../components/markdown-with-mentions";
5
- import { Tooltip } from "../../components/tooltip";
6
- import { useObservableState } from "../../hooks";
7
- import { getCronErrors, getCronExplanation } from "./cron";
8
-
9
- export const PeerEventSchedule = (props: { peerEventType: IDoc<IPeerEventType> }) => {
10
- const { peerEventType } = props;
11
-
12
- return (
13
- <div>
14
-
15
- <div className="mt-3"></div>
16
- <small>Chron Schedule</small>
17
- <CronScheduleEditor cronSchedule={peerEventType.qs.cronSchedule} q={peerEventType.q} />
18
-
19
- </div>
20
- );
21
- };
22
-
23
- const CronScheduleEditor = (props: { cronSchedule: Observable<string | undefined>, q: Observable<number> }) => {
24
- const { cronSchedule } = props;
25
- const tempSchedule = useObservableState(props.cronSchedule() ?? '');
26
- const cronError = useObservableState('');
27
- const cronExplanation = useObservableState('');
28
-
29
- const emptyCronMessage = [
30
- 'Enter a valid cron schedule to have this workflow automatically run.',
31
- 'For detailed information, see [Cron Schedule Syntax](https://en.wikipedia.org/wiki/Cron#CRON_expression)',
32
- 'and [CronTab.Guru](https://crontab.guru/)\n',
33
- 'The format is:',
34
- '- `minute hour day-of-month month day-of-week`. ',
35
- ' - `*` means every',
36
- ' - `1-5` means 1 through 5',
37
- ' - `1,4` means 1 and 4',
38
- '',
39
- 'Examples:',
40
- '- run every day at 3am:\n - `0 3 * * *`',
41
- '- run every Monday at 3am:\n - `0 3 * * 1`',
42
- '- run every Monday and Thursday at 3am:\n - `0 3 * * 1,4`',
43
- '- run every weekday at 3am:\n - `0 3 * * 1-5`',
44
-
45
- ].join('\n')
46
-
47
-
48
- useEffect(() => {
49
-
50
- function updateExplanation() {
51
- if (cronError()) {
52
- cronExplanation('');
53
- }
54
- else if (!tempSchedule()) {
55
- cronExplanation(emptyCronMessage);
56
- }
57
- else {
58
- cronExplanation(getCronExplanation(tempSchedule()));
59
- }
60
- }
61
-
62
- cronExplanation(getCronExplanation(tempSchedule()));
63
-
64
- const sub = tempSchedule.subscribe(() => {
65
- // validate and format cron schedule
66
- let schedule = tempSchedule() || '';
67
- schedule = schedule.trim();
68
- cronExplanation('');
69
- cronError('');
70
- cronSchedule(undefined);
71
- if (!schedule) {
72
- updateExplanation();
73
- return;
74
- }
75
-
76
- const errors = getCronErrors(schedule);
77
- if (errors) {
78
- cronError(errors);
79
- return;
80
- }
81
-
82
- cronSchedule(schedule);
83
- updateExplanation();
84
- });
85
-
86
- const sub2 = props.q.subscribe(() => {
87
- if (props.q() === 0) {
88
- tempSchedule(cronSchedule() || '');
89
- cronError('');
90
- cronExplanation(getCronExplanation(tempSchedule()));
91
- }
92
- })
93
- return () => {
94
- sub.dispose();
95
- sub2.dispose();
96
- }
97
- }, [cronSchedule, tempSchedule]);
98
-
99
-
100
- return (
101
- <>
102
- <Tooltip
103
- markdownContent={emptyCronMessage}
104
- handleClassName={`p-2 small`}
105
- />
106
-
107
- <Input
108
- value={tempSchedule}
109
- className={`form-control mb-3 p-0 p-2 ` + (cronError() ? 'border-danger' : '')}
110
- placeholder="minute hour day(of month) month day(of week)"
111
- title="Cron Schedule"
112
- style={{ fontFamily: 'monospace' }}
113
- />
114
- {cronError()
115
- ? (
116
- <div className="text-danger">
117
- <MarkdownWithMentions content={cronError()} />
118
- </div>
119
- )
120
- : (
121
- <div>
122
- <MarkdownWithMentions content={cronExplanation()} />
123
- </div>
124
- )
125
- }
126
-
127
-
128
- </>
129
- )
130
- }