├── .editorconfig
├── .eslintrc
├── .github
└── workflows
│ ├── alpha.yml
│ └── release.yml
├── .gitignore
├── .storybook
├── main.js
└── preview.js
├── .vscode
└── extensions.json
├── README.MD
├── browserslist
├── cypress.config.ts
├── cypress
├── component
│ ├── app.tsx
│ ├── container.tsx
│ ├── localization.ts
│ └── test.cy.tsx
├── fixtures
│ └── example.json
└── support
│ ├── commands.ts
│ ├── component-index.html
│ └── component.ts
├── package-lock.json
├── package.json
├── prepare-package.mjs
├── src
├── lib
│ ├── cron-base-props.type.ts
│ ├── cron-base-tab-props.type.ts
│ ├── cron-localization.ts
│ ├── cron-props.type.ts
│ ├── cron.ts
│ ├── helpers.ts
│ ├── index.ts
│ ├── quartz
│ │ ├── index.ts
│ │ ├── quartz.tsx
│ │ └── tabs
│ │ │ ├── day
│ │ │ └── day.tsx
│ │ │ ├── hour
│ │ │ └── hour.tsx
│ │ │ ├── index.ts
│ │ │ ├── minute
│ │ │ └── minute.tsx
│ │ │ ├── month
│ │ │ └── month.tsx
│ │ │ ├── second
│ │ │ └── second.tsx
│ │ │ ├── shared
│ │ │ ├── increment.tsx
│ │ │ ├── index.ts
│ │ │ └── tab-props.type.ts
│ │ │ └── year
│ │ │ └── year.tsx
│ ├── shared
│ │ ├── and.tsx
│ │ ├── every.tsx
│ │ ├── index.ts
│ │ ├── props.type.ts
│ │ └── range.tsx
│ └── unix
│ │ ├── index.ts
│ │ ├── tabs
│ │ ├── day
│ │ │ └── day.tsx
│ │ ├── hour
│ │ │ └── hour.tsx
│ │ ├── index.ts
│ │ ├── minute
│ │ │ └── minute.tsx
│ │ ├── month
│ │ │ └── month.tsx
│ │ └── shared
│ │ │ ├── increment.tsx
│ │ │ ├── index.ts
│ │ │ └── tab-props.type.ts
│ │ └── unix.tsx
└── stories
│ ├── Introduction.stories.mdx
│ ├── assets
│ ├── code-brackets.svg
│ ├── colors.svg
│ ├── comments.svg
│ ├── direction.svg
│ ├── flow.svg
│ ├── plugin.svg
│ ├── repo.svg
│ └── stackalt.svg
│ ├── quartz-cron.stories.tsx
│ └── unix-cron.stories.tsx
├── tsconfig.base.json
└── tsconfig.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.md]
12 | max_line_length = off
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "parser": "@typescript-eslint/parser",
4 | "plugins": [
5 | "@typescript-eslint"
6 | ],
7 | "extends": [
8 | "eslint:recommended",
9 | "plugin:@typescript-eslint/eslint-recommended",
10 | "plugin:@typescript-eslint/recommended"
11 | ],
12 | "rules": {
13 | "indent": ["error", 2]
14 | },
15 | "ignorePatterns": [
16 | "dist",
17 | "coverage",
18 | "node_modules"
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/.github/workflows/alpha.yml:
--------------------------------------------------------------------------------
1 | name: Alpha
2 |
3 | on:
4 | push:
5 | branches:
6 | - 'feature/**'
7 |
8 | jobs:
9 | build:
10 |
11 | runs-on: ubuntu-latest
12 |
13 | strategy:
14 | matrix:
15 | node-version: [16.16.0]
16 |
17 | steps:
18 | - uses: actions/checkout@v3
19 | - name: Use Node.js ${{ matrix.node-version }}
20 | uses: actions/setup-node@v3
21 | with:
22 | node-version: ${{ matrix.node-version }}
23 | - name: Get npm cache directory
24 | id: npm-cache-dir
25 | run: |
26 | echo "::set-output name=dir::$(npm config get cache)"
27 | - name: Cache node modules
28 | uses: actions/cache@v3
29 | id: npm-cache
30 | with:
31 | path: ${{ steps.npm-cache-dir.outputs.dir }}
32 | key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
33 | restore-keys: |
34 | ${{ runner.os }}-node-
35 | - name: Install Dependencies
36 | run: npm ci
37 | env:
38 | CI: true
39 | - name: Linting
40 | run: npm run lint
41 | env:
42 | CI: true
43 | - name: Units Testing
44 | run: npm run e2e-run
45 | env:
46 | CI: true
47 | - name: Publish Test Report
48 | uses: mikepenz/action-junit-report@v3
49 | if: always() # always run even if the previous step fails
50 | with:
51 | report_paths: 'e2e-results/**/*.xml'
52 | - name: Build Dist
53 | run: npm run build-alpha
54 | env:
55 | CI: true
56 | - name: Npm Configuration
57 | run: npm config set //registry.npmjs.org/:_authToken=$NODE_AUTH_TOKEN
58 | env:
59 | CI: true
60 | NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}
61 | - name: Publish Cron Core
62 | run: npm run publish-alpha
63 | env:
64 | CI: true
65 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | push:
5 | branches:
6 | main
7 |
8 | jobs:
9 | build:
10 |
11 | runs-on: ubuntu-latest
12 |
13 | strategy:
14 | matrix:
15 | node-version: [16.16.0]
16 |
17 | steps:
18 | - uses: actions/checkout@v3
19 | - name: Use Node.js ${{ matrix.node-version }}
20 | uses: actions/setup-node@v3
21 | with:
22 | node-version: ${{ matrix.node-version }}
23 | - name: Get npm cache directory
24 | id: npm-cache-dir
25 | run: |
26 | echo "::set-output name=dir::$(npm config get cache)"
27 | - name: Cache node modules
28 | uses: actions/cache@v3
29 | id: npm-cache
30 | with:
31 | path: ${{ steps.npm-cache-dir.outputs.dir }}
32 | key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
33 | restore-keys: |
34 | ${{ runner.os }}-node-
35 | - name: Install Dependencies
36 | run: npm ci
37 | env:
38 | CI: true
39 | - name: Linting
40 | run: npm run lint
41 | env:
42 | CI: true
43 | - name: Units Testing
44 | run: npm run e2e-run
45 | env:
46 | CI: true
47 | - name: Publish Test Report
48 | uses: mikepenz/action-junit-report@v3
49 | if: always() # always run even if the previous step fails
50 | with:
51 | report_paths: 'e2e-results/**/*.xml'
52 | - name: Build Dist
53 | run: npm run build
54 | env:
55 | CI: true
56 | - name: Npm Configuration
57 | run: npm config set //registry.npmjs.org/:_authToken=$NODE_AUTH_TOKEN
58 | env:
59 | CI: true
60 | NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}
61 | - name: Publish Cron Core
62 | run: npm run publish
63 | env:
64 | CI: true
65 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | storybook-static
4 | e2e-results
5 | cypress/videos
6 |
--------------------------------------------------------------------------------
/.storybook/main.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | core: {
3 | builder: 'webpack5',
4 | },
5 | "stories": [
6 | "../src/stories/**/*.stories.mdx",
7 | "../src/stories/**/*.stories.@(js|jsx|ts|tsx)"
8 | ],
9 | "addons": [
10 | "@storybook/addon-links",
11 | "@storybook/addon-essentials",
12 | "@storybook/addon-interactions",
13 | {
14 | "name": "storybook-addon-sass-postcss",
15 | "options": {
16 | sassLoaderOptions: {
17 | implementation: require('sass'),
18 | }
19 | }
20 | }
21 | ],
22 | "framework": "@storybook/react"
23 | }
24 |
--------------------------------------------------------------------------------
/.storybook/preview.js:
--------------------------------------------------------------------------------
1 | import '!style-loader!css-loader!sass-loader!bootstrap/scss/bootstrap.scss'
2 |
3 | export const parameters = {
4 | actions: { argTypesRegex: "^on[A-Z].*" },
5 | controls: {
6 | matchers: {
7 | color: /(background|color)$/i,
8 | date: /Date$/,
9 | },
10 | },
11 | }
12 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "nrwl.angular-console",
4 | "esbenp.prettier-vscode",
5 | "firsttris.vscode-jest-runner",
6 | "dbaeumer.vscode-eslint"
7 | ]
8 | }
9 |
--------------------------------------------------------------------------------
/README.MD:
--------------------------------------------------------------------------------
1 | [](https://vshymanskyy.github.io/StandWithUkraine)
2 |
3 | # Quartz/Unix Cron Component - React
4 |
5 | [React](https://reactjs.org/) cron widget built from the ground up using only [Bootstrap 4](https://getbootstrap.com/) CSS.
6 |
7 | Please check our [demo & documentation](https://recron.emptyui.com) and the list of
8 | [issues](https://github.com/ua-cron/react/issues) to see all the things we are working on. Feel free to make comments there.
9 |
10 |
11 |
12 |
16 |
17 |
18 |
19 |
20 |
21 |
24 |
25 |
26 |
29 |
30 |
31 |
32 | ## Getting Started
33 |
34 | This is an open source project that builds a cron builder component for React applications.
35 | It supports Quartz/Unix cron string formats for both input and output.
36 | Inspired by this [non-react](https://www.freeformatter.com/cron-expression-generator-quartz.html) implementation.
37 |
38 | ## Installation
39 | You can use either the npm or yarn command-line tool to install packages.
40 | ```
41 | npm install --save @sbzen/re-cron
42 | ```
43 |
44 | ## Display the cron component
45 | Import and add the cron component into your jsx/tsx.
46 |
47 | ```tsx
48 | import React, { useState } from 'react';
49 | import { ReQuartzCron } from '@sbzen/re-cron';
50 |
51 | const App = () => {
52 | const [value, setValue] = useState('2,0,4,3,1 0/1 3/2 ? * 4/5 *');
53 |
54 | return (
55 |
58 | );
59 | };
60 | export default App;
61 | ```
62 |
63 | ## Usage & Demo
64 | Main source of API documentation and usage scenarios available here: https://recron.emptyui.com.
65 |
66 |
67 | ## Compatibility
68 | The only two required dependencies are React and cron-core.
69 | The Bootstrap CSS is optional as you can use this component with your own styling.
70 | Here is the versions compatibility list:
71 |
72 | | Re Cron | React | Bootstrap CSS |
73 | | ------------- | ------------- | -------------- |
74 | | 0.0.1 | 16.x.x | 4.x.x |
75 | | 2.0.0 | 17.x.x | 4.x.x |
76 |
--------------------------------------------------------------------------------
/browserslist:
--------------------------------------------------------------------------------
1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
2 | # For additional information regarding the format and rule options, please see:
3 | # https://github.com/browserslist/browserslist#queries
4 |
5 | # You can see what browsers were selected by your queries by running:
6 | # npx browserslist
7 |
8 | > 0.5%
9 | last 2 versions
10 | Firefox ESR
11 | not dead
12 | not IE 9-11 # For IE 9-11 support, remove 'not'.
13 |
--------------------------------------------------------------------------------
/cypress.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "cypress";
2 |
3 | export default defineConfig({
4 | fileServerFolder: './',
5 | component: {
6 | numTestsKeptInMemory: 0,
7 | devServer: {
8 | framework: "create-react-app",
9 | bundler: "webpack",
10 | },
11 | reporter: 'junit',
12 | reporterOptions: {
13 | mochaFile: 'e2e-results/test-result-[hash].xml',
14 | includePending: true,
15 | attachments: true,
16 | outputs: true
17 | }
18 | }
19 | });
20 |
--------------------------------------------------------------------------------
/cypress/component/app.tsx:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from 'react';
2 | import { ReUnixCron, ReQuartzCron, Tab } from '@sbzen/re-cron';
3 |
4 | import { TestContainer } from './container';
5 |
6 | export const App = () => {
7 | return (
8 |
9 | }/>
14 |
15 | }/>
19 |
20 | );
21 | };
22 |
23 | export default App;
24 |
--------------------------------------------------------------------------------
/cypress/component/container.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { Tab, CronLocalization } from '@sbzen/re-cron';
3 |
4 | import { getLocalizationPathes, getLocalization } from './localization';
5 |
6 | export const TestContainer = ({
7 | type = '',
8 | render,
9 | initialValue,
10 | initialTabs = [Tab.SECONDS, Tab.MINUTES, Tab.HOURS, Tab.DAY, Tab.MONTH, Tab.YEAR]
11 | }) => {
12 | const [value, setValue] = useState(initialValue);
13 | const [disabled, setDisabled] = useState(false);
14 | const [hideTabs, setHideTabs] = useState(false);
15 | const [cssClassPrefix, setCssClassPrefix] = useState(undefined);
16 | const [activeTab, setActiveTab] = useState(undefined);
17 | const [localization, setLocalization] = useState(undefined);
18 | const [tabs, setTabs] = useState(undefined);
19 |
20 | const getLocalizationValue = (path: string, loc = getLocalization()) => {
21 | const paths = path.split('.');
22 | const lastProp = paths[paths.length - 1];
23 | const store = paths.slice(0, paths.length - 1).reduce((acc, prop) => acc[prop], loc);
24 | return store[lastProp];
25 | }
26 |
27 | const updateLocalizationField = (path: string, localizationValue: string) => {
28 | if (!localization) {
29 | return;
30 | }
31 | const paths = path.split('.');
32 | const lastProp = paths[paths.length - 1];
33 | const store = paths.slice(0, paths.length - 1).reduce((acc, prop) => acc[prop], localization);
34 | store[lastProp] = localizationValue;
35 | setLocalization({ ...localization });
36 | };
37 |
38 | const addedTab = (tab: Tab) => (tabs || []).includes(tab);
39 |
40 | const toggleTab = (tab: Tab) => {
41 | const tabsToUse = tabs || [];
42 | if (addedTab(tab)) {
43 | setTabs(tabsToUse.filter(t => t !== tab));
44 | return;
45 | }
46 | setTabs([
47 | ...tabsToUse,
48 | tab
49 | ]);
50 | };
51 |
52 | return (
53 |
56 |
57 |
{type}
58 |
59 |
setValue(e.target.value)}/>
63 |
64 |
setLocalization(undefined)}>
68 | Reset Localization
69 |
70 |
setLocalization(localization || getLocalization())}>
74 | Use Localization
75 |
76 |
setDisabled(!disabled)}>
80 | Disable
81 |
82 |
setHideTabs(true)}>
86 | Hide tabs
87 |
88 |
setHideTabs(false)}>
92 | Show tabs
93 |
94 |
setCssClassPrefix('my-')}>
98 | Add "my-" css prefix
99 |
100 |
setCssClassPrefix(undefined)}>
104 | Remove "my-" css prefix
105 |
106 |
107 |
108 | {getLocalizationPathes().map((path, i) => (
109 | updateLocalizationField(path, e.target.value)}/>
118 | ))}
119 |
120 |
121 |
122 | setTabs(undefined)}>
126 | Reset Tabs
127 |
128 | setTabs([])}>
132 | Remove Tabs
133 |
134 | {initialTabs.map((tab, i) => (
135 | toggleTab(tab)}>
141 | {tab}
142 | {addedTab(tab) ? '-' : '+'}
143 |
144 | ))}
145 |
146 |
147 |
148 | {initialTabs.map((tab, i) => (
149 | setActiveTab(tab)}>
155 | {tab}
156 |
157 | ))}
158 |
159 |
160 |
161 | {activeTab}
162 |
163 |
164 |
165 | {render({
166 | value,
167 | cssClassPrefix,
168 | localization,
169 | activeTab,
170 | tabs,
171 | onChange: setValue,
172 | hideTabs,
173 | onTabChange: setActiveTab,
174 | disabled
175 | })}
176 |
177 |
178 | );
179 | };
180 |
--------------------------------------------------------------------------------
/cypress/component/localization.ts:
--------------------------------------------------------------------------------
1 | import { CronLocalization } from '@sbzen/re-cron';
2 |
3 | export const getLocalizationPathes = (obj: CronLocalization = getLocalization(), parentProp = '') => {
4 | return Object.keys(obj).reduce((acc, prop) => {
5 | const propsLine = [parentProp, prop].filter(a => !!a).join('.');
6 |
7 | const value = obj[prop];
8 | let values: string[] = [];
9 |
10 | if (typeof value !== 'string') {
11 | values = getLocalizationPathes(value, propsLine);
12 | } else {
13 | values = [propsLine];
14 | }
15 |
16 | return [
17 | ...acc,
18 | ...values
19 | ];
20 | }, [] as string[]);
21 | };
22 |
23 | export const getLocalization = (): CronLocalization => ({
24 | common: {
25 | month: {
26 | january: 'January',
27 | february: 'February',
28 | march: 'March',
29 | april: 'April',
30 | may: 'May',
31 | june: 'June',
32 | july: 'July',
33 | august: 'August',
34 | september: 'September',
35 | october: 'October',
36 | november: 'November',
37 | december: 'December'
38 | },
39 | dayOfWeek: {
40 | sunday: 'Sunday',
41 | monday: 'Monday',
42 | tuesday: 'Tuesday',
43 | wednesday: 'Wednesday',
44 | thursday: 'Thursday',
45 | friday: 'Friday',
46 | saturday: 'Saturday'
47 | },
48 | dayOfMonth: {
49 | '1st': '1st',
50 | '2nd': '2nd',
51 | '3rd': '3rd',
52 | '4th': '4th',
53 | '5th': '5th',
54 | '6th': '6th',
55 | '7th': '7th',
56 | '8th': '8th',
57 | '9th': '9th',
58 | '10th': '10th',
59 | '11th': '11th',
60 | '12th': '12th',
61 | '13th': '13th',
62 | '14th': '14th',
63 | '15th': '15th',
64 | '16th': '16th',
65 | '17th': '17th',
66 | '18th': '18th',
67 | '19th': '19th',
68 | '20th': '20th',
69 | '21st': '21st',
70 | '22nd': '22nd',
71 | '23rd': '23rd',
72 | '24th': '24th',
73 | '25th': '25th',
74 | '26th': '26th',
75 | '27th': '27th',
76 | '28th': '28th',
77 | '29th': '29th',
78 | '30th': '30th',
79 | '31st': '31st'
80 | }
81 | },
82 | tabs: {
83 | seconds: 'Seconds',
84 | minutes: 'Minutes',
85 | hours: 'Hours',
86 | day: 'Day',
87 | month: 'Month',
88 | year: 'Year'
89 | },
90 | quartz: {
91 | day: {
92 | every: {
93 | label: 'Every day'
94 | },
95 | dayOfWeekIncrement: {
96 | label1: 'Every',
97 | label2: 'day(s) starting on'
98 | },
99 | dayOfMonthIncrement: {
100 | label1: 'Every',
101 | label2: 'day(s) starting on the',
102 | label3: 'of the month'
103 | },
104 | dayOfWeekAnd: {
105 | label: 'Specific day of week (choose one or many)'
106 | },
107 | dayOfWeekRange: {
108 | label1: 'Every day between',
109 | label2: 'and'
110 | },
111 | dayOfMonthAnd: {
112 | label: 'Specific day of month (choose one or many)'
113 | },
114 | dayOfMonthLastDay: {
115 | label: 'On the last day of the month'
116 | },
117 | dayOfMonthLastDayWeek: {
118 | label: 'On the last weekday of the month'
119 | },
120 | dayOfWeekLastNTHDayWeek: {
121 | label1: 'On the last',
122 | label2: 'of the month'
123 | },
124 | dayOfMonthDaysBeforeEndMonth: {
125 | label: 'day(s) before the end of the month'
126 | },
127 | dayOfMonthNearestWeekDayOfMonth: {
128 | label1: 'Nearest weekday (Monday to Friday) to the',
129 | label2: 'of the month'
130 | },
131 | dayOfWeekNTHWeekDayOfMonth: {
132 | label1: 'On the',
133 | label2: 'of the month'
134 | }
135 | },
136 | month: {
137 | every: {
138 | label: 'Every month'
139 | },
140 | increment: {
141 | label1: 'Every',
142 | label2: 'month(s) starting at month',
143 | },
144 | and: {
145 | label: 'Specific month (choose one or many)'
146 | },
147 | range: {
148 | label1: 'Every month between month',
149 | label2: 'and month'
150 | }
151 | },
152 | second: {
153 | every: {
154 | label: 'Every second'
155 | },
156 | increment: {
157 | label1: 'Every',
158 | label2: 'second(s) starting at second',
159 | },
160 | and: {
161 | label: 'Specific second (choose one or many)'
162 | },
163 | range: {
164 | label1: 'Every second between second',
165 | label2: 'and second'
166 | }
167 | },
168 | minute: {
169 | every: {
170 | label: 'Every minute'
171 | },
172 | increment: {
173 | label1: 'Every',
174 | label2: 'minute(s) starting at minute',
175 | },
176 | and: {
177 | label: 'Specific minute (choose one or many)'
178 | },
179 | range: {
180 | label1: 'Every minute between minute',
181 | label2: 'and minute'
182 | }
183 | },
184 | hour: {
185 | every: {
186 | label: 'Every hour'
187 | },
188 | increment: {
189 | label1: 'Every',
190 | label2: 'hour(s) starting at hour',
191 | },
192 | and: {
193 | label: 'Specific hour (choose one or many)'
194 | },
195 | range: {
196 | label1: 'Every hour between hour',
197 | label2: 'and hour'
198 | }
199 | },
200 | year: {
201 | every: {
202 | label: 'Any year'
203 | },
204 | increment: {
205 | label1: 'Every',
206 | label2: 'year(s) starting at year',
207 | },
208 | and: {
209 | label: 'Specific year (choose one or many)'
210 | },
211 | range: {
212 | label1: 'Every year between year',
213 | label2: 'and year'
214 | }
215 | }
216 | },
217 | unix: {
218 | day: {
219 | every: {
220 | label: 'Every day'
221 | },
222 | dayOfWeekIncrement: {
223 | label1: 'Every',
224 | label2: 'day(s) of week'
225 | },
226 | dayOfMonthIncrement: {
227 | label1: 'Every',
228 | label2: 'day(s) of month'
229 | },
230 | dayOfWeekAnd: {
231 | label: 'Specific day of week (choose one or many)'
232 | },
233 | dayOfMonthAnd: {
234 | label: 'Specific day of month (choose one or many)'
235 | }
236 | },
237 | month: {
238 | every: {
239 | label: 'Every month'
240 | },
241 | increment: {
242 | label1: 'Every',
243 | label2: 'month(s)',
244 | },
245 | and: {
246 | label: 'Specific month (choose one or many)'
247 | },
248 | range: {
249 | label1: 'Every month between month',
250 | label2: 'and month'
251 | }
252 | },
253 | minute: {
254 | every: {
255 | label: 'Every minute'
256 | },
257 | increment: {
258 | label1: 'Every',
259 | label2: 'minute(s)',
260 | },
261 | and: {
262 | label: 'Specific minute (choose one or many)'
263 | },
264 | range: {
265 | label1: 'Every minute between minute',
266 | label2: 'and minute'
267 | }
268 | },
269 | hour: {
270 | every: {
271 | label: 'Every hour'
272 | },
273 | increment: {
274 | label1: 'Every',
275 | label2: 'hour(s)',
276 | },
277 | and: {
278 | label: 'Specific hour (choose one or many)'
279 | },
280 | range: {
281 | label1: 'Every hour between hour',
282 | label2: 'and hour'
283 | }
284 | }
285 | }
286 | });
287 |
--------------------------------------------------------------------------------
/cypress/component/test.cy.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { mount } from '@cypress/react'
3 |
4 | import { activeTab, cssClasses, localization, disabled, tabChange, tabs, hideTabs, values } from '@sbzen/e2e';
5 |
6 | import { App } from './app';
7 |
8 | const beforeEachCb = () => beforeEach(() => mount( ));
9 |
10 | activeTab(beforeEachCb);
11 | cssClasses(beforeEachCb, false);
12 | localization(beforeEachCb);
13 | disabled(beforeEachCb);
14 | tabChange(beforeEachCb);
15 | tabs(beforeEachCb);
16 | hideTabs(beforeEachCb);
17 | values(beforeEachCb);
18 |
--------------------------------------------------------------------------------
/cypress/fixtures/example.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Using fixtures to represent data",
3 | "email": "hello@cypress.io",
4 | "body": "Fixtures are a great way to mock data for responses to routes"
5 | }
6 |
--------------------------------------------------------------------------------
/cypress/support/commands.ts:
--------------------------------------------------------------------------------
1 | ///
2 | // ***********************************************
3 | // This example commands.ts shows you how to
4 | // create various custom commands and overwrite
5 | // existing commands.
6 | //
7 | // For more comprehensive examples of custom
8 | // commands please read more here:
9 | // https://on.cypress.io/custom-commands
10 | // ***********************************************
11 | //
12 | //
13 | // -- This is a parent command --
14 | // Cypress.Commands.add('login', (email, password) => { ... })
15 | //
16 | //
17 | // -- This is a child command --
18 | // Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
19 | //
20 | //
21 | // -- This is a dual command --
22 | // Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
23 | //
24 | //
25 | // -- This will overwrite an existing command --
26 | // Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
27 | //
28 | // declare global {
29 | // namespace Cypress {
30 | // interface Chainable {
31 | // login(email: string, password: string): Chainable
32 | // drag(subject: string, options?: Partial): Chainable
33 | // dismiss(subject: string, options?: Partial): Chainable
34 | // visit(originalFn: CommandOriginalFn, url: string, options: Partial): Chainable
35 | // }
36 | // }
37 | // }
--------------------------------------------------------------------------------
/cypress/support/component-index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Components App
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/cypress/support/component.ts:
--------------------------------------------------------------------------------
1 | // ***********************************************************
2 | // This example support/component.ts is processed and
3 | // loaded automatically before your test files.
4 | //
5 | // This is a great place to put global configuration and
6 | // behavior that modifies Cypress.
7 | //
8 | // You can change the location of this file or turn off
9 | // automatically serving support files with the
10 | // 'supportFile' configuration option.
11 | //
12 | // You can read more here:
13 | // https://on.cypress.io/configuration
14 | // ***********************************************************
15 |
16 | // Import commands.js using ES2015 syntax:
17 | import './commands'
18 |
19 | // Alternatively you can use CommonJS syntax:
20 | // require('./commands')
21 |
22 | import { mount } from 'cypress/react'
23 |
24 | // Augment the Cypress namespace to include type definitions for
25 | // your custom command.
26 | // Alternatively, can be defined in cypress/support/component.d.ts
27 | // with a at the top of your spec.
28 | declare global {
29 | // eslint-disable-next-line
30 | namespace Cypress {
31 | interface Chainable {
32 | mount: typeof mount
33 | }
34 | }
35 | }
36 |
37 | Cypress.Commands.add('mount', mount)
38 |
39 | // Example use:
40 | // cy.mount( )
41 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@sbzen/re-cron",
3 | "version": "2.0.7",
4 | "description": "Quartz Cron Component - React",
5 | "author": "Serhii Bzenko ",
6 | "license": "MIT",
7 | "repository": {
8 | "type": "git",
9 | "url": "git+ssh://git@github.com/ua-cron/react.git"
10 | },
11 | "keywords": [
12 | "react",
13 | "bootstap",
14 | "cron",
15 | "quartz",
16 | "cron builder",
17 | "cron generator",
18 | "quartz cron"
19 | ],
20 | "homepage": "https://recron.emptyui.com",
21 | "sideEffects": false,
22 | "bugs": {
23 | "url": "https://github.com/ua-cron/react/issues"
24 | },
25 | "scripts": {
26 | "copy-rm": "cp README.MD dist/README.MD",
27 | "build": "npm run clean && tsc && node prepare-package.mjs && npm run copy-rm",
28 | "build-alpha": "ALPHA=1 npm run build",
29 | "clean": "rm -rf dist",
30 | "test-debug": "node --inspect-brk node_modules/.bin/jest --runInBand",
31 | "test": "jest",
32 | "lint": "eslint . --ext .ts --ext .tsx",
33 | "storybook": "start-storybook -p 6006",
34 | "build-storybook": "build-storybook",
35 | "e2e-inject": "npm install ./dist --force",
36 | "e2e": "npm run build && npm run e2e-inject && npx cypress open --component",
37 | "e2e-run": "npm run build && npm run e2e-inject && npx cypress run --component",
38 | "publish-alpha": "npm publish ./dist --tag alpha --access=public",
39 | "publish": "npm publish ./dist"
40 | },
41 | "dependencies": {
42 | "@sbzen/cron-core": "2.0.3"
43 | },
44 | "peerDependencies": {
45 | "react": "*",
46 | "react-dom": "*"
47 | },
48 | "devDependencies": {
49 | "@babel/core": "^7.18.6",
50 | "@babel/preset-typescript": "^7.18.6",
51 | "@cypress/react": "^6.1.0",
52 | "@sbzen/e2e": "https://github.com/ua-cron/e2e/releases/download/20240602212421/dist.tar.gz",
53 | "@storybook/addon-actions": "^6.5.10",
54 | "@storybook/addon-essentials": "^6.5.10",
55 | "@storybook/addon-interactions": "^6.5.10",
56 | "@storybook/addon-links": "^6.5.10",
57 | "@storybook/builder-webpack5": "^6.5.10",
58 | "@storybook/manager-webpack5": "^6.5.10",
59 | "@storybook/react": "^6.5.10",
60 | "@storybook/testing-library": "0.0.13",
61 | "@types/jest": "^27.5.1",
62 | "@types/lodash": "^4.14.182",
63 | "@types/node": "^17.0.35",
64 | "@types/react": "^17.0.2",
65 | "@typescript-eslint/eslint-plugin": "^5.30.0",
66 | "@typescript-eslint/parser": "^5.30.0",
67 | "babel-loader": "^8.2.5",
68 | "bootstrap": "^4.6.1",
69 | "eslint": "^8.18.0",
70 | "jest": "^28.1.0",
71 | "lodash": "^4.17.21",
72 | "react-scripts": "^5.0.1",
73 | "sass": "^1.53.0",
74 | "storybook-addon-sass-postcss": "^0.1.3",
75 | "ts-jest": "^28.0.2",
76 | "ts-node": "^10.8.0",
77 | "typescript": "4.6.4"
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/prepare-package.mjs:
--------------------------------------------------------------------------------
1 | import { readFileSync, writeFileSync } from 'fs';
2 | import { resolve, dirname } from 'path';
3 | import { fileURLToPath } from 'url';
4 | import { env } from 'node:process';
5 |
6 | const isAlpha = env.ALPHA;
7 | const __dirname = dirname(fileURLToPath(import.meta.url));
8 | const distLibPath = resolve(__dirname, './dist');
9 | const packagePath = resolve(__dirname, './package.json');
10 |
11 | const packageString = readFileSync(packagePath);
12 | const {
13 | name,
14 | version,
15 | author,
16 | homepage,
17 | keywords,
18 | license,
19 | repository,
20 | sideEffects,
21 | dependencies,
22 | peerDependencies,
23 | bugs
24 | } = JSON.parse(packageString);
25 |
26 | const nextVersion = isAlpha ? `${version}-alpha.${Date.now()}` : version;
27 | const nextDependencies = Object.keys(dependencies).reduce((acc, prop) => {
28 | if (prop === name) {
29 | return acc;
30 | }
31 | return {
32 | ...acc,
33 | [prop]: dependencies[prop]
34 | }
35 | }, {});
36 |
37 | const libPackage = JSON.stringify({
38 | name,
39 | version: nextVersion,
40 | author,
41 | license,
42 | keywords,
43 | repository,
44 | homepage,
45 | dependencies: nextDependencies,
46 | peerDependencies,
47 | sideEffects,
48 | bugs,
49 | main: 'index.js',
50 | types: 'index.d.ts'
51 | }, null, ' ');
52 |
53 | writeFileSync(resolve(distLibPath, './package.json'), libPackage);
54 |
--------------------------------------------------------------------------------
/src/lib/cron-base-props.type.ts:
--------------------------------------------------------------------------------
1 | export type CronBaseProps = {
2 | cssClassPrefix?: string
3 | };
4 |
--------------------------------------------------------------------------------
/src/lib/cron-base-tab-props.type.ts:
--------------------------------------------------------------------------------
1 | import { CronUnixUIService, CronQuartzUIService } from '@sbzen/cron-core';
2 |
3 | import { CronBaseProps } from './cron-base-props.type';
4 | import { localization } from './cron-localization';
5 |
6 | export type CronBaseTabProps = {
7 | localization: typeof localization,
8 | session: string,
9 | service: T
10 | } & CronBaseProps;
11 |
--------------------------------------------------------------------------------
/src/lib/cron-localization.ts:
--------------------------------------------------------------------------------
1 | export const localization = {
2 | common: {
3 | month: {
4 | january: 'January',
5 | february: 'February',
6 | march: 'March',
7 | april: 'April',
8 | may: 'May',
9 | june: 'June',
10 | july: 'July',
11 | august: 'August',
12 | september: 'September',
13 | october: 'October',
14 | november: 'November',
15 | december: 'December'
16 | },
17 | dayOfWeek: {
18 | sunday: 'Sunday',
19 | monday: 'Monday',
20 | tuesday: 'Tuesday',
21 | wednesday: 'Wednesday',
22 | thursday: 'Thursday',
23 | friday: 'Friday',
24 | saturday: 'Saturday'
25 | },
26 | dayOfMonth: {
27 | '1st': '1st',
28 | '2nd': '2nd',
29 | '3rd': '3rd',
30 | '4th': '4th',
31 | '5th': '5th',
32 | '6th': '6th',
33 | '7th': '7th',
34 | '8th': '8th',
35 | '9th': '9th',
36 | '10th': '10th',
37 | '11th': '11th',
38 | '12th': '12th',
39 | '13th': '13th',
40 | '14th': '14th',
41 | '15th': '15th',
42 | '16th': '16th',
43 | '17th': '17th',
44 | '18th': '18th',
45 | '19th': '19th',
46 | '20th': '20th',
47 | '21st': '21st',
48 | '22nd': '22nd',
49 | '23rd': '23rd',
50 | '24th': '24th',
51 | '25th': '25th',
52 | '26th': '26th',
53 | '27th': '27th',
54 | '28th': '28th',
55 | '29th': '29th',
56 | '30th': '30th',
57 | '31st': '31st'
58 | }
59 | },
60 | tabs: {
61 | seconds: 'Seconds',
62 | minutes: 'Minutes',
63 | hours: 'Hours',
64 | day: 'Day',
65 | month: 'Month',
66 | year: 'Year'
67 | },
68 | quartz: {
69 | day: {
70 | every: {
71 | label: 'Every day'
72 | },
73 | dayOfWeekIncrement: {
74 | label1: 'Every',
75 | label2: 'day(s) starting on'
76 | },
77 | dayOfMonthIncrement: {
78 | label1: 'Every',
79 | label2: 'day(s) starting on the',
80 | label3: 'of the month'
81 | },
82 | dayOfWeekAnd: {
83 | label: 'Specific day of week (choose one or many)'
84 | },
85 | dayOfWeekRange: {
86 | label1: 'Every day between',
87 | label2: 'and'
88 | },
89 | dayOfMonthAnd: {
90 | label: 'Specific day of month (choose one or many)'
91 | },
92 | dayOfMonthLastDay: {
93 | label: 'On the last day of the month'
94 | },
95 | dayOfMonthLastDayWeek: {
96 | label: 'On the last weekday of the month'
97 | },
98 | dayOfWeekLastNTHDayWeek: {
99 | label1: 'On the last',
100 | label2: 'of the month'
101 | },
102 | dayOfMonthDaysBeforeEndMonth: {
103 | label: 'day(s) before the end of the month'
104 | },
105 | dayOfMonthNearestWeekDayOfMonth: {
106 | label1: 'Nearest weekday (Monday to Friday) to the',
107 | label2: 'of the month'
108 | },
109 | dayOfWeekNTHWeekDayOfMonth: {
110 | label1: 'On the',
111 | label2: 'of the month'
112 | }
113 | },
114 | month: {
115 | every: {
116 | label: 'Every month'
117 | },
118 | increment: {
119 | label1: 'Every',
120 | label2: 'month(s) starting at month',
121 | },
122 | and: {
123 | label: 'Specific month (choose one or many)'
124 | },
125 | range: {
126 | label1: 'Every month between month',
127 | label2: 'and month'
128 | }
129 | },
130 | second: {
131 | every: {
132 | label: 'Every second'
133 | },
134 | increment: {
135 | label1: 'Every',
136 | label2: 'second(s) starting at second',
137 | },
138 | and: {
139 | label: 'Specific second (choose one or many)'
140 | },
141 | range: {
142 | label1: 'Every second between second',
143 | label2: 'and second'
144 | }
145 | },
146 | minute: {
147 | every: {
148 | label: 'Every minute'
149 | },
150 | increment: {
151 | label1: 'Every',
152 | label2: 'minute(s) starting at minute',
153 | },
154 | and: {
155 | label: 'Specific minute (choose one or many)'
156 | },
157 | range: {
158 | label1: 'Every minute between minute',
159 | label2: 'and minute'
160 | }
161 | },
162 | hour: {
163 | every: {
164 | label: 'Every hour'
165 | },
166 | increment: {
167 | label1: 'Every',
168 | label2: 'hour(s) starting at hour',
169 | },
170 | and: {
171 | label: 'Specific hour (choose one or many)'
172 | },
173 | range: {
174 | label1: 'Every hour between hour',
175 | label2: 'and hour'
176 | }
177 | },
178 | year: {
179 | every: {
180 | label: 'Any year'
181 | },
182 | increment: {
183 | label1: 'Every',
184 | label2: 'year(s) starting at year',
185 | },
186 | and: {
187 | label: 'Specific year (choose one or many)'
188 | },
189 | range: {
190 | label1: 'Every year between year',
191 | label2: 'and year'
192 | }
193 | }
194 | },
195 | unix: {
196 | day: {
197 | every: {
198 | label: 'Every day'
199 | },
200 | dayOfWeekIncrement: {
201 | label1: 'Every',
202 | label2: 'day(s) of week'
203 | },
204 | dayOfMonthIncrement: {
205 | label1: 'Every',
206 | label2: 'day(s) of month'
207 | },
208 | dayOfWeekAnd: {
209 | label: 'Specific day of week (choose one or many)'
210 | },
211 | dayOfMonthAnd: {
212 | label: 'Specific day of month (choose one or many)'
213 | }
214 | },
215 | month: {
216 | every: {
217 | label: 'Every month'
218 | },
219 | increment: {
220 | label1: 'Every',
221 | label2: 'month(s)',
222 | },
223 | and: {
224 | label: 'Specific month (choose one or many)'
225 | },
226 | range: {
227 | label1: 'Every month between month',
228 | label2: 'and month'
229 | }
230 | },
231 | minute: {
232 | every: {
233 | label: 'Every minute'
234 | },
235 | increment: {
236 | label1: 'Every',
237 | label2: 'minute(s)',
238 | },
239 | and: {
240 | label: 'Specific minute (choose one or many)'
241 | },
242 | range: {
243 | label1: 'Every minute between minute',
244 | label2: 'and minute'
245 | }
246 | },
247 | hour: {
248 | every: {
249 | label: 'Every hour'
250 | },
251 | increment: {
252 | label1: 'Every',
253 | label2: 'hour(s)',
254 | },
255 | and: {
256 | label: 'Specific hour (choose one or many)'
257 | },
258 | range: {
259 | label1: 'Every hour between hour',
260 | label2: 'and hour'
261 | }
262 | }
263 | }
264 | };
265 |
266 | export type DeepPartial = {
267 | [P in keyof T]?: DeepPartial;
268 | };
269 |
270 | export type CronLocalization = DeepPartial;
271 |
--------------------------------------------------------------------------------
/src/lib/cron-props.type.ts:
--------------------------------------------------------------------------------
1 | import { Type } from '@sbzen/cron-core';
2 |
3 | import { CronBaseProps } from './cron-base-props.type';
4 | import { CronLocalization } from './cron-localization';
5 |
6 | export type CronHostProps = {
7 | localization?: CronLocalization,
8 | hideTabs?: boolean,
9 | value?: string,
10 | activeTab?: T,
11 | tabs?: T[],
12 | disabled?: boolean,
13 | renderYearsFrom?: number,
14 | renderYearsTo?: number,
15 | onChange?: (cronValue: string) => void,
16 | onTabChange?: (tab: T) => void
17 | } & CronBaseProps;
18 |
--------------------------------------------------------------------------------
/src/lib/cron.ts:
--------------------------------------------------------------------------------
1 | export { ReQuartzCron as ReCron } from './quartz';
2 |
--------------------------------------------------------------------------------
/src/lib/helpers.ts:
--------------------------------------------------------------------------------
1 | import { Mode } from '@sbzen/cron-core';
2 |
3 | import { DeepPartial, localization, CronLocalization } from './cron-localization';
4 |
5 | export const genSessionId = () => `${Date.now()}_${Math.random()}`;
6 |
7 | export const genClassName = (cssClassPrefix = '', classes: string[], noPrefixClasses: string[] = []) => {
8 | const prefixed = classes.filter(c => !!c).map(c => cssClassPrefix + c);
9 | return prefixed.concat(noPrefixClasses).join(' ');
10 | };
11 |
12 | export const genId = (mode: Mode, session: string, extra?: string) => {
13 | return `${mode}-${extra || ''}${session}`;
14 | };
15 |
16 | export const getCssClassPrefix = (cssClassPrefix?: string) => cssClassPrefix || '';
17 |
18 | export const localizeList = (list: { value: string, label: string }[], localizationStore: { [key: string]: string }) => {
19 | return list.map(v => ({
20 | ...v,
21 | label: localizeLabel(v.label, localizationStore)
22 | }));
23 | }
24 |
25 | export const localizeLabel = (label: string, localizationStore: { [key: string]: string }) => {
26 | return localizationStore[label.toLowerCase()]
27 | }
28 |
29 | export const getLocalization = (input?: CronLocalization) => {
30 | const args: RawObject[] = [localization];
31 | if (input) {
32 | args.push(input);
33 | }
34 | return mergeDeep(...args);
35 | }
36 |
37 | type RawObject = DeepPartial<{
38 | [key: string]: string|RawObject;
39 | }>;
40 | const mergeDeep = (...objects: RawObject[]) => {
41 | return objects.reduce((prev, obj) => {
42 | Object.keys(obj).forEach(key => {
43 | const pVal = prev[key];
44 | const oVal = obj[key];
45 |
46 | if (pVal && typeof pVal === 'object' && oVal && typeof oVal === 'object') {
47 | prev[key] = mergeDeep(pVal, oVal);
48 | } else {
49 | prev[key] = oVal;
50 | }
51 | });
52 |
53 | return prev;
54 | }, {}) as T;
55 | }
56 |
--------------------------------------------------------------------------------
/src/lib/index.ts:
--------------------------------------------------------------------------------
1 | export { Type as Tab } from '@sbzen/cron-core';
2 | export { CronLocalization } from './cron-localization';
3 | export * from './cron';
4 | export * from './unix';
5 | export * from './quartz';
6 |
--------------------------------------------------------------------------------
/src/lib/quartz/index.ts:
--------------------------------------------------------------------------------
1 | export * from './quartz';
--------------------------------------------------------------------------------
/src/lib/quartz/quartz.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import {
3 | CronQuartzUIService,
4 | QuartzType,
5 | Type,
6 | getSegmentsList,
7 | getTypeSegments,
8 | getQuartzTypes
9 | } from '@sbzen/cron-core';
10 |
11 | import { getLocalization, genSessionId, genClassName } from './../helpers';
12 | import { CronHostProps } from './../cron-props.type';
13 | import {
14 | QuartzCronSecond,
15 | QuartzCronMinute,
16 | QuartzCronHour,
17 | QuartzCronMonth,
18 | QuartzCronYear,
19 | QuartzCronDay
20 | } from './tabs';
21 |
22 | export type ReQuartzCronProps = CronHostProps;
23 | export const ReQuartzCron = ({
24 | localization: propLocalization,
25 | hideTabs: propHideTabs,
26 | value = '',
27 | activeTab,
28 | tabs = getQuartzTypes(),
29 | renderYearsFrom,
30 | renderYearsTo,
31 | cssClassPrefix,
32 | disabled,
33 | onTabChange,
34 | onChange
35 | }: ReQuartzCronProps) => {
36 | const [tab, setTab] = useState(activeTab || tabs[0]);
37 | const [service] = useState(new CronQuartzUIService(renderYearsFrom));
38 | const [renderCount, setRenderCount] = useState(0);
39 | const [session] = useState(genSessionId());
40 | const localization = getLocalization(propLocalization);
41 | const hasTabs = !propHideTabs && !!tabs.length;
42 | const tabProps = {
43 | cssClassPrefix,
44 | localization,
45 | session,
46 | service
47 | };
48 | const yearTabProps = {
49 | ...tabProps,
50 | renderYearsFrom,
51 | renderYearsTo
52 | };
53 |
54 | useEffect(() => {
55 | const shouldUpdate = !!activeTab && activeTab !== tab;
56 | shouldUpdate && setTab(activeTab);
57 | }, [activeTab]);
58 | useEffect(() => () => service.destroy(), [service]);
59 | useEffect(() => listenChangas());
60 | useEffect(() => service.fillFromExpression(value), [value]);
61 | useEffect(() => service.setDisabled(disabled), [disabled]);
62 |
63 | const listenChangas = () => {
64 | const segments = getSegmentsList();
65 | return service.listen(segments, (_, segment) => {
66 | const shouldApply = getTypeSegments(tab).includes(segment);
67 | if (shouldApply) {
68 | applyChanges();
69 | }
70 | });
71 | };
72 |
73 | const genContent = () => {
74 | if (tab === Type.SECONDS) {
75 | return ;
76 | } else if (tab === Type.MINUTES) {
77 | return ;
78 | } else if (tab === Type.HOURS) {
79 | return ;
80 | } else if (tab === Type.MONTH) {
81 | return ;
82 | } else if (tab === Type.YEAR) {
83 | return ;
84 | } else {
85 | return ;
86 | }
87 | };
88 |
89 | const genTabs = (activeTab: QuartzType) => {
90 | const className = genClassName(cssClassPrefix, ['nav', 'nav-tabs', 'mb-2'], ['c-tabs']);
91 | return (
92 |
96 |
97 | {tabs.map(t => genTab(t, activeTab))}
98 |
99 | );
100 | };
101 |
102 | const genTab = (tab: QuartzType, activeTab: QuartzType) => {
103 | const { tabs: tabsLocalization } = localization;
104 | const isActive = activeTab === tab;
105 | const className = genClassName(cssClassPrefix, ['nav-link', isActive ? 'active': ''], [tab, 'c-tab']);
106 | const tabKey = tab.toLowerCase() as keyof typeof tabsLocalization;
107 |
108 | return (
109 |
112 |
113 | changeTab(tab)}>
120 |
121 | {tabsLocalization[tabKey]}
122 |
123 |
124 | );
125 | };
126 |
127 | const changeTab = (tab: QuartzType) => {
128 | setTab(tab);
129 | if (onTabChange) {
130 | onTabChange(tab);
131 | }
132 | };
133 |
134 | const applyChanges = () => {
135 | const str = service.toString();
136 | if (str !== value && onChange) {
137 | onChange(str);
138 | }
139 | setRenderCount(renderCount + 1);
140 | };
141 |
142 | return (
143 |
144 | {hasTabs && genTabs(tab)}
145 |
146 |
152 | {genContent()}
153 |
154 |
155 | );
156 | };
157 |
158 | export default ReQuartzCron;
159 |
--------------------------------------------------------------------------------
/src/lib/quartz/tabs/day/day.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Segment, Mode, Type, getDaysOfWeekCodes, getList } from '@sbzen/cron-core';
3 |
4 | import { genId, getCssClassPrefix, localizeLabel, genClassName, localizeList } from './../../../helpers';
5 | import { SimpleRange } from './../../../shared';
6 | import { CronQuartzTabProps } from './../shared';
7 |
8 | export const QuartzCronDay = ({
9 | service,
10 | session,
11 | localization,
12 | cssClassPrefix
13 | }: CronQuartzTabProps) => {
14 | const { common, quartz } = localization;
15 | const {
16 | every,
17 | dayOfWeekIncrement,
18 | dayOfMonthLastDay,
19 | dayOfWeekNTHWeekDayOfMonth,
20 | dayOfMonthNearestWeekDayOfMonth,
21 | dayOfMonthDaysBeforeEndMonth,
22 | dayOfWeekLastNTHDayWeek,
23 | dayOfMonthLastDayWeek,
24 | dayOfMonthIncrement,
25 | dayOfWeekAnd,
26 | dayOfWeekRange,
27 | dayOfMonthAnd
28 | } = quartz.day;
29 | const classPrefix = getCssClassPrefix(cssClassPrefix);
30 | const api = service.getApi(Type.DAY);
31 | const daysOfWeekEvery = getList(Segment.dayOfWeek, true);
32 | const daysOfWeek = getList(Segment.dayOfWeek);
33 | const daysOfWeekCodes = getDaysOfWeekCodes();
34 | const daysOfMonthEvery = getList(Segment.dayOfMonth, true);
35 | const daysOfMonth = getList(Segment.dayOfMonth);
36 | const limitedDaysOfMonth = daysOfMonthEvery.slice(0, 5);
37 |
38 | const genEvery = () => (
39 |
40 |
41 | api.selectEvery()} />
49 |
50 |
53 |
54 | {every.label}
55 |
56 |
57 |
58 | );
59 |
60 | const genDayOfWeekIncrement = () => (
61 |
62 |
63 | api.selectDayOfWeekIncrement()} />
71 |
72 |
75 |
76 | {dayOfWeekIncrement.label1}
77 |
78 |
79 |
80 |
api.setDayOfWeekIncrementPrimary(e.target.value)}>
85 |
86 | {daysOfWeekEvery.map(item => {
87 | return (
88 |
91 | {item.value}
92 |
93 | );
94 | })}
95 |
96 |
97 |
100 | {dayOfWeekIncrement.label2}
101 |
102 |
103 |
api.setDayOfWeekIncrementSecondary(e.target.value)}>
108 |
109 | {daysOfWeek.map(item => {
110 | return (
111 |
114 | {localizeLabel(item.label, common.dayOfWeek)}
115 |
116 | );
117 | })}
118 |
119 |
120 | );
121 |
122 | const genDayOfMonthIncrement = () => (
123 |
124 |
125 | api.selectDayOfMonthIncrement()} />
133 |
134 |
137 | {dayOfMonthIncrement.label1}
138 |
139 |
140 |
141 |
api.setDayOfMonthIncrementPrimary(e.target.value)}>
146 |
147 | {daysOfMonth.map(item => {
148 | return (
149 |
152 | {item.value}
153 |
154 | );
155 | })}
156 |
157 |
158 |
161 | {dayOfMonthIncrement.label2}
162 |
163 |
164 |
api.setDayOfMonthIncrementSecondary(e.target.value)}>
169 |
170 | {daysOfMonthEvery.map(item => {
171 | return (
172 |
175 | {localizeLabel(item.label, common.dayOfMonth)}
176 |
177 | );
178 | })}
179 |
180 |
181 |
184 | {dayOfMonthIncrement.label3}
185 |
186 |
187 | );
188 |
189 | const genDayOfWeekAnd = () => (
190 |
191 |
192 | api.selectDayOfWeekAnd()} />
200 |
201 |
204 | {dayOfWeekAnd.label}
205 |
206 |
207 |
208 |
209 | {daysOfWeekCodes.map(item => {
210 | return (
211 |
215 |
216 |
217 | api.selectDayOfWeekAndValue(item.value)} />
225 |
226 |
229 | {localizeLabel(item.label, common.dayOfWeek)}
230 |
231 |
232 |
233 | );
234 | })}
235 |
236 |
237 | );
238 |
239 | const getDayOfWeekRange = () => (
240 | api.selectDayOfWeekRange()}
246 | disabledControls={api.isDayOfWeekRangeControlsDisabled()}
247 | label1={dayOfWeekRange.label1}
248 | label2={dayOfWeekRange.label2}
249 | primaryOptions={localizeList(daysOfWeekCodes, common.dayOfWeek)}
250 | primaryValue={api.getDayOfWeekRangePrimary()}
251 | onPrimaryValueChange={api.setDayOfWeekRangePrimary}
252 | secondaryOptions={localizeList(daysOfWeekCodes, common.dayOfWeek)}
253 | secondaryValue={api.getDayOfWeekRangeSecondary()}
254 | onSecondaryValueChange={api.setDayOfWeekRangeSecondary}/>
255 | );
256 |
257 | const genDayOfMonthAnd = () => (
258 |
259 |
260 | api.selectDayOfMonthAnd()} />
268 |
269 |
272 | {dayOfMonthAnd.label}
273 |
274 |
275 |
276 |
277 | {daysOfMonth.map(item => {
278 | return (
279 |
283 |
284 |
285 | api.selectDayOfMonthAndValue(item.value)} />
293 |
294 |
297 | {item.label}
298 |
299 |
300 |
301 | );
302 | })}
303 |
304 |
305 | );
306 |
307 | const genDayOfMonthLastDay = () => (
308 |
309 |
310 | api.selectDayOfMonthLastDay()} />
318 |
319 |
322 | {dayOfMonthLastDay.label}
323 |
324 |
325 |
326 | );
327 |
328 | const genDayOfMonthLastDayWeek = () => (
329 |
330 |
331 | api.selectDayOfMonthLastDayWeek()} />
339 |
340 |
343 | {dayOfMonthLastDayWeek.label}
344 |
345 |
346 |
347 | );
348 |
349 | const genDayOfWeekLastNTHDayWeek = () => (
350 |
351 |
352 | api.selectDayOfWeekLastNTHDayWeek()} />
360 |
361 |
364 |
365 | {dayOfWeekLastNTHDayWeek.label1}
366 |
367 |
368 |
369 |
api.setDayOfWeekLastNTHDayWeekValue(e.target.value)}>
374 |
375 | {daysOfWeek.map(item => {
376 | return (
377 |
380 | {localizeLabel(item.label, common.dayOfWeek)}
381 |
382 | );
383 | })}
384 |
385 |
386 |
389 | {dayOfWeekLastNTHDayWeek.label2}
390 |
391 |
392 | );
393 |
394 | const genDayOfMonthDaysBeforeEndMonth = () => (
395 |
396 |
397 | api.selectDayOfMonthDaysBeforeEndMonth()} />
405 |
406 |
407 |
api.setDayOfMonthDaysBeforeEndMonthValue(e.target.value)}>
412 |
413 | {daysOfMonth.map(item => {
414 | return (
415 |
418 | {item.label}
419 |
420 | );
421 | })}
422 |
423 |
424 |
427 | {dayOfMonthDaysBeforeEndMonth.label}
428 |
429 |
430 | );
431 |
432 | const genDayOfMonthNearestWeekDayOfMonth = () => (
433 |
434 |
435 | api.selectDayOfMonthNearestWeekDayOfMonth()} />
443 |
444 |
447 | {dayOfMonthNearestWeekDayOfMonth.label1}
448 |
449 |
450 |
451 |
api.setDayOfMonthNearestWeekDayOfMonthValue(e.target.value)}>
456 |
457 | {daysOfMonthEvery.map(item => {
458 | return (
459 |
462 | {localizeLabel(item.label, common.dayOfMonth)}
463 |
464 | );
465 | })}
466 |
467 |
468 |
471 | {dayOfMonthNearestWeekDayOfMonth.label2}
472 |
473 |
474 | );
475 |
476 | const genDayOfWeekNTHWeekDayOfMonth = () => (
477 |
478 |
479 | api.selectDayOfWeekNTHWeekDayOfMonth()} />
487 |
488 |
491 | {dayOfWeekNTHWeekDayOfMonth.label1}
492 |
493 |
494 |
495 |
api.setDayOfWeekNTHWeekDayOfMonthPrimaryValue(e.target.value)}>
500 |
501 | {limitedDaysOfMonth.map(item => {
502 | return (
503 |
506 | {localizeLabel(item.label, common.dayOfMonth)}
507 |
508 | );
509 | })}
510 |
511 |
512 |
api.setDayOfWeekNTHWeekDayOfMonthSecondaryValue(e.target.value)}>
517 |
518 | {daysOfWeek.map(item => {
519 | return (
520 |
523 | {localizeLabel(item.label, common.dayOfWeek)}
524 |
525 | );
526 | })}
527 |
528 |
529 |
532 | {dayOfWeekNTHWeekDayOfMonth.label2}
533 |
534 |
535 | );
536 |
537 | return (
538 |
539 | {genEvery()}
540 | {genDayOfWeekIncrement()}
541 | {genDayOfMonthIncrement()}
542 | {genDayOfWeekAnd()}
543 | {getDayOfWeekRange()}
544 | {genDayOfMonthAnd()}
545 | {genDayOfMonthLastDay()}
546 | {genDayOfMonthLastDayWeek()}
547 | {genDayOfWeekLastNTHDayWeek()}
548 | {genDayOfMonthDaysBeforeEndMonth()}
549 | {genDayOfMonthNearestWeekDayOfMonth()}
550 | {genDayOfWeekNTHWeekDayOfMonth()}
551 |
552 | );
553 | }
554 |
--------------------------------------------------------------------------------
/src/lib/quartz/tabs/hour/hour.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Segment, Mode, Type, getList } from '@sbzen/cron-core';
3 |
4 | import { SimpleEvery, SimpleAnd, SimpleRange } from './../../../shared';
5 | import { genId, getCssClassPrefix } from './../../../helpers';
6 | import { SimpleIncrement, CronQuartzTabProps } from './../shared';
7 |
8 | export const QuartzCronHour = ({
9 | service,
10 | session,
11 | localization,
12 | cssClassPrefix
13 | }: CronQuartzTabProps) => {
14 | const { every, increment, and, range } = localization.quartz.hour;
15 | const classPrefix = getCssClassPrefix(cssClassPrefix);
16 | const api = service.getApi(Type.HOURS);
17 | const hourCodes = getList(Segment.hours, true);
18 | const hoursList = getList(Segment.hours);
19 |
20 | const genEvery = () => (
21 | api.selectEvery()}
27 | label={every.label}/>
28 | );
29 |
30 | const genIncrement = () => (
31 | api.selectIncrement()}
38 | label1={increment.label1}
39 | label2={increment.label2}
40 | primaryOptions={hourCodes}
41 | primaryValue={api.getIncrementPrimaryValue()}
42 | onPrimaryValueChange={api.setIncrementPrimaryValue}
43 | secondaryOptions={hoursList}
44 | secondaryValue={api.getIncrementSecondaryValue()}
45 | onSecondaryValueChange={api.setIncrementSecondaryValue}/>
46 | );
47 |
48 | const genAnd = () => (
49 | api.selectAnd()}
56 | label={and.label}
57 | onValueChange={api.selectAndValue}
58 | isValueSelected={value => api.isSelectedAndValue(value)}
59 | options={hoursList}/>
60 | );
61 |
62 | const genRange = () => (
63 | api.selectRange()}
69 | disabledControls={api.isRangeControlsDisabled()}
70 | label1={range.label1}
71 | label2={range.label2}
72 | primaryOptions={hoursList}
73 | primaryValue={api.getRangePrimaryValue()}
74 | onPrimaryValueChange={api.setRangePrimaryValue}
75 | secondaryOptions={hoursList}
76 | secondaryValue={api.getRangeSecondaryValue()}
77 | onSecondaryValueChange={api.setRangeSecondaryValue}/>
78 | );
79 |
80 | return (
81 |
82 | {genEvery()}
83 | {genIncrement()}
84 | {genAnd()}
85 | {genRange()}
86 |
87 | );
88 | }
89 |
--------------------------------------------------------------------------------
/src/lib/quartz/tabs/index.ts:
--------------------------------------------------------------------------------
1 | export * from './day/day';
2 | export * from './hour/hour';
3 | export * from './minute/minute';
4 | export * from './month/month';
5 | export * from './second/second';
6 | export * from './year/year';
--------------------------------------------------------------------------------
/src/lib/quartz/tabs/minute/minute.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Segment, Mode, Type, getList } from '@sbzen/cron-core';
3 |
4 | import { SimpleEvery, SimpleAnd, SimpleRange } from './../../../shared';
5 | import { genId, getCssClassPrefix } from './../../../helpers';
6 | import { SimpleIncrement, CronQuartzTabProps } from './../shared';
7 |
8 | export const QuartzCronMinute = ({
9 | service,
10 | session,
11 | localization,
12 | cssClassPrefix
13 | }: CronQuartzTabProps) => {
14 | const { every, increment, and, range } = localization.quartz.minute;
15 | const classPrefix = getCssClassPrefix(cssClassPrefix);
16 | const api = service.getApi(Type.MINUTES);
17 | const minutesList = getList(Segment.minutes);
18 | const minuteCodes = getList(Segment.minutes, true);
19 |
20 | const genEvery = () => (
21 | api.selectEvery()}
27 | label={every.label}/>
28 | );
29 |
30 | const genIncrement = () => (
31 | api.selectIncrement()}
38 | label1={increment.label1}
39 | label2={increment.label2}
40 | primaryOptions={minuteCodes}
41 | primaryValue={api.getIncrementPrimaryValue()}
42 | onPrimaryValueChange={api.setIncrementPrimaryValue}
43 | secondaryOptions={minutesList}
44 | secondaryValue={api.getIncrementSecondaryValue()}
45 | onSecondaryValueChange={api.setIncrementSecondaryValue}/>
46 | );
47 |
48 | const genAnd = () => (
49 | api.selectAnd()}
56 | label={and.label}
57 | onValueChange={api.selectAndValue}
58 | isValueSelected={value => api.isSelectedAndValue(value)}
59 | options={minutesList}/>
60 | );
61 |
62 | const genRange = () => (
63 | api.selectRange()}
69 | disabledControls={api.isRangeControlsDisabled()}
70 | label1={range.label1}
71 | label2={range.label2}
72 | primaryOptions={minutesList}
73 | primaryValue={api.getRangePrimaryValue()}
74 | onPrimaryValueChange={api.setRangePrimaryValue}
75 | secondaryOptions={minutesList}
76 | secondaryValue={api.getRangeSecondaryValue()}
77 | onSecondaryValueChange={api.setRangeSecondaryValue}/>
78 | );
79 |
80 | return (
81 |
82 | {genEvery()}
83 | {genIncrement()}
84 | {genAnd()}
85 | {genRange()}
86 |
87 | );
88 | }
89 |
--------------------------------------------------------------------------------
/src/lib/quartz/tabs/month/month.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Segment, Mode, Type, getMonthCodes, getList } from '@sbzen/cron-core';
3 |
4 | import { genId, getCssClassPrefix, localizeList } from './../../../helpers';
5 | import { SimpleEvery, SimpleAnd, SimpleRange } from './../../../shared';
6 | import { SimpleIncrement, CronQuartzTabProps } from './../shared';
7 |
8 | export const QuartzCronMonth = ({
9 | service,
10 | localization,
11 | session,
12 | cssClassPrefix
13 | }: CronQuartzTabProps) => {
14 | const { common, quartz } = localization;
15 | const { every, increment, and, range } = quartz.month;
16 | const classPrefix = getCssClassPrefix(cssClassPrefix);
17 | const api = service.getApi(Type.MONTH);
18 | const monthCodes = getMonthCodes();
19 | const monthes = getList(Segment.month);
20 |
21 | const genEvery = () => (
22 | api.selectEvery()}
28 | label={every.label}/>
29 | );
30 |
31 | const genIncrement = () => (
32 | api.selectIncrement()}
39 | label1={increment.label1}
40 | label2={increment.label2}
41 | primaryOptions={monthes.map(({ value }, i) => ({ value, label: i + 1 }))}
42 | primaryValue={api.getIncrementPrimaryValue()}
43 | onPrimaryValueChange={api.setIncrementPrimaryValue}
44 | secondaryOptions={localizeList(monthes, common.month)}
45 | secondaryValue={api.getIncrementSecondaryValue()}
46 | onSecondaryValueChange={api.setIncrementSecondaryValue}/>
47 | );
48 |
49 | const genAnd = () => (
50 | api.selectAnd()}
58 | label={and.label}
59 | onValueChange={api.selectAndValue}
60 | isValueSelected={value => api.isSelectedAndValue(value)}
61 | options={localizeList(monthCodes, common.month)}/>
62 | );
63 |
64 | const genRange = () => (
65 | api.selectRange()}
71 | disabledControls={api.isRangeControlsDisabled()}
72 | label1={range.label1}
73 | label2={range.label2}
74 | primaryOptions={localizeList(monthes, common.month)}
75 | primaryValue={api.getRangePrimaryValue()}
76 | onPrimaryValueChange={api.setRangePrimaryValue}
77 | secondaryOptions={localizeList(monthes, common.month)}
78 | secondaryValue={api.getRangeSecondaryValue()}
79 | onSecondaryValueChange={api.setRangeSecondaryValue}/>
80 | );
81 |
82 | return (
83 |
84 | {genEvery()}
85 | {genIncrement()}
86 | {genAnd()}
87 | {genRange()}
88 |
89 | );
90 | }
91 |
--------------------------------------------------------------------------------
/src/lib/quartz/tabs/second/second.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Segment, Mode, Type, getList } from '@sbzen/cron-core';
3 |
4 | import { SimpleEvery, SimpleAnd, SimpleRange } from './../../../shared';
5 | import { genId, getCssClassPrefix } from './../../../helpers';
6 | import { SimpleIncrement, CronQuartzTabProps } from './../shared';
7 |
8 | export const QuartzCronSecond = (props: CronQuartzTabProps) => {
9 | const { service, localization, session, cssClassPrefix } = props;
10 | const { every, increment, and, range } = localization.quartz.second;
11 | const classPrefix = getCssClassPrefix(cssClassPrefix);
12 | const api = service.getApi(Type.SECONDS);
13 | const secondCodes = getList(Segment.seconds, true);
14 | const secondsList = getList(Segment.seconds);
15 |
16 | const genEvery = () => (
17 | api.selectEvery()}
23 | label={every.label}/>
24 | );
25 |
26 | const genIncrement = () => (
27 | api.selectIncrement()}
34 | label1={increment.label1}
35 | label2={increment.label2}
36 | primaryOptions={secondCodes}
37 | primaryValue={api.getIncrementPrimaryValue()}
38 | onPrimaryValueChange={api.setIncrementPrimaryValue}
39 | secondaryOptions={secondsList}
40 | secondaryValue={api.getIncrementSecondaryValue()}
41 | onSecondaryValueChange={api.setIncrementSecondaryValue}/>
42 | );
43 |
44 | const genAnd = () => (
45 | api.selectAnd()}
52 | label={and.label}
53 | onValueChange={api.selectAndValue}
54 | isValueSelected={value => api.isSelectedAndValue(value)}
55 | options={secondsList}/>
56 | );
57 |
58 | const genRange = () => (
59 | api.selectRange()}
65 | disabledControls={api.isRangeControlsDisabled()}
66 | label1={range.label1}
67 | label2={range.label2}
68 | primaryOptions={secondsList}
69 | primaryValue={api.getRangePrimaryValue()}
70 | onPrimaryValueChange={api.setRangePrimaryValue}
71 | secondaryOptions={secondsList}
72 | secondaryValue={api.getRangeSecondaryValue()}
73 | onSecondaryValueChange={api.setRangeSecondaryValue}/>
74 | );
75 |
76 | return (
77 |
78 | {genEvery()}
79 | {genIncrement()}
80 | {genAnd()}
81 | {genRange()}
82 |
83 | );
84 | }
85 |
--------------------------------------------------------------------------------
/src/lib/quartz/tabs/shared/increment.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Mode } from '@sbzen/cron-core';
3 |
4 | import { CronBaseProps } from './../../../cron-base-props.type';
5 | import { genClassName } from '../../../helpers';
6 |
7 | type Props = {
8 | checked?: boolean,
9 | disabled?: boolean,
10 | disabledControls?: boolean,
11 | onSelect: () => void,
12 | primaryOptions: {
13 | label: string|number,
14 | value: string
15 | }[];
16 | primaryValue: string,
17 | onPrimaryValueChange: (value: string) => void,
18 | secondaryOptions: {
19 | label: string|number,
20 | value: string
21 | }[],
22 | secondaryValue: string,
23 | onSecondaryValueChange: (value: string) => void,
24 | label1: string,
25 | label2: string,
26 | segmentId: string
27 | } & CronBaseProps;
28 |
29 | export const SimpleIncrement = ({
30 | cssClassPrefix = '',
31 | checked = false,
32 | disabled = false,
33 | disabledControls = false,
34 | label1,
35 | label2,
36 | onSelect,
37 | primaryOptions,
38 | primaryValue,
39 | onPrimaryValueChange,
40 | secondaryOptions,
41 | secondaryValue,
42 | onSecondaryValueChange,
43 | segmentId
44 | }: Props) => (
45 |
46 |
47 |
55 |
56 |
59 | {label1}
60 |
61 |
62 |
63 |
onPrimaryValueChange(e.target.value)}>
68 |
69 | {primaryOptions.map(item => {
70 | return (
71 |
74 | {item.label}
75 |
76 | );
77 | })}
78 |
79 |
80 |
83 | {label2}
84 |
85 |
86 |
onSecondaryValueChange(e.target.value)}>
91 |
92 | {secondaryOptions.map(item => {
93 | return (
94 |
97 | {item.label}
98 |
99 | );
100 | })}
101 |
102 |
103 | );
104 |
--------------------------------------------------------------------------------
/src/lib/quartz/tabs/shared/index.ts:
--------------------------------------------------------------------------------
1 | export * from './increment';
2 | export * from './tab-props.type';
3 |
--------------------------------------------------------------------------------
/src/lib/quartz/tabs/shared/tab-props.type.ts:
--------------------------------------------------------------------------------
1 | import { CronQuartzUIService } from '@sbzen/cron-core';
2 |
3 | import { CronBaseTabProps } from './../../../cron-base-tab-props.type';
4 |
5 | export type CronQuartzTabProps = CronBaseTabProps;
6 |
--------------------------------------------------------------------------------
/src/lib/quartz/tabs/year/year.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Segment, Mode, Type, getList } from '@sbzen/cron-core';
3 |
4 | import { SimpleEvery, SimpleAnd, SimpleRange } from './../../../shared';
5 | import { genId, getCssClassPrefix } from './../../../helpers';
6 | import { SimpleIncrement, CronQuartzTabProps } from './../shared';
7 |
8 | export type CronTabYearProps = {
9 | renderYearsFrom?: number,
10 | renderYearsTo?: number
11 | } & CronQuartzTabProps;
12 |
13 | export const QuartzCronYear = (props: CronTabYearProps) => {
14 | const { service, localization, session, cssClassPrefix, renderYearsFrom, renderYearsTo } = props;
15 | const { every, increment, and, range } = localization.quartz.year;
16 | const classPrefix = getCssClassPrefix(cssClassPrefix);
17 | const api = service.getApi(Type.YEAR);
18 | const yearCodes = getList(Segment.year, true);
19 | const years = getList(Segment.year, false, renderYearsFrom, renderYearsTo);
20 |
21 | const genEvery = () => (
22 | api.selectEvery()}
28 | label={every.label}/>
29 | );
30 |
31 | const genIncrement = () => (
32 | api.selectIncrement()}
39 | label1={increment.label1}
40 | label2={increment.label2}
41 | primaryOptions={yearCodes}
42 | primaryValue={api.getIncrementPrimaryValue()}
43 | onPrimaryValueChange={api.setIncrementPrimaryValue}
44 | secondaryOptions={years}
45 | secondaryValue={api.getIncrementSecondaryValue()}
46 | onSecondaryValueChange={api.setIncrementSecondaryValue}/>
47 | );
48 |
49 | const genAnd = () => (
50 | api.selectAnd()}
57 | label={and.label}
58 | onValueChange={api.selectAndValue}
59 | isValueSelected={value => api.isSelectedAndValue(value)}
60 | options={years}/>
61 | );
62 |
63 | const genRange = () => (
64 | api.selectRange()}
70 | disabledControls={api.isRangeControlsDisabled()}
71 | label1={range.label1}
72 | label2={range.label2}
73 | primaryOptions={years}
74 | primaryValue={api.getRangePrimaryValue()}
75 | onPrimaryValueChange={api.setRangePrimaryValue}
76 | secondaryOptions={years}
77 | secondaryValue={api.getRangeSecondaryValue()}
78 | onSecondaryValueChange={api.setRangeSecondaryValue}/>
79 | );
80 |
81 | return (
82 |
83 | {genEvery()}
84 | {genIncrement()}
85 | {genAnd()}
86 | {genRange()}
87 |
88 | );
89 | }
90 |
--------------------------------------------------------------------------------
/src/lib/shared/and.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Mode } from '@sbzen/cron-core';
3 |
4 | import { genClassName } from './../helpers';
5 | import { SharedProps } from './props.type';
6 |
7 | type Props = {
8 | disabledControls?: boolean;
9 | onValueChange: (value: string) => void;
10 | isValueSelected: (value: string) => boolean;
11 | options: {
12 | label: string,
13 | value: string
14 | }[],
15 | label: string;
16 | gridSize?: string[];
17 | } & SharedProps;
18 |
19 | export const SimpleAnd = ({
20 | cssClassPrefix = '',
21 | checked = false,
22 | disabled = false,
23 | disabledControls = false,
24 | label,
25 | options,
26 | onSelect,
27 | onValueChange,
28 | isValueSelected,
29 | gridSize = ['col-2', 'col-md-1'],
30 | segmentId
31 | }: Props) => (
32 |
33 |
34 |
42 |
43 |
46 | {label}
47 |
48 |
49 |
50 |
51 | {options.map(item => {
52 | return (
53 |
57 |
58 |
59 | onValueChange(item.value)} />
67 |
68 |
71 | {item.label}
72 |
73 |
74 |
75 | );
76 | })}
77 |
78 |
79 | );
80 |
--------------------------------------------------------------------------------
/src/lib/shared/every.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Mode } from '@sbzen/cron-core';
3 |
4 | import { genClassName } from './../helpers';
5 | import { SharedProps } from './props.type';
6 |
7 | type Props = {
8 | label: string;
9 | } & SharedProps;
10 |
11 | export const SimpleEvery = ({
12 | cssClassPrefix = '',
13 | checked = false,
14 | disabled = false,
15 | label,
16 | onSelect,
17 | segmentId
18 | }: Props) => (
19 |
20 |
21 |
29 |
30 |
33 | {label}
34 |
35 |
36 |
37 | );
38 |
--------------------------------------------------------------------------------
/src/lib/shared/index.ts:
--------------------------------------------------------------------------------
1 | export * from './and';
2 | export * from './every';
3 | export * from './range';
--------------------------------------------------------------------------------
/src/lib/shared/props.type.ts:
--------------------------------------------------------------------------------
1 | import { CronBaseProps } from './../cron-base-props.type';
2 |
3 | export type SharedProps = {
4 | segmentId: string,
5 | disabled?: boolean,
6 | checked?: boolean,
7 | onSelect: () => void
8 | } & CronBaseProps;
9 |
--------------------------------------------------------------------------------
/src/lib/shared/range.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Mode } from '@sbzen/cron-core';
3 |
4 | import { genClassName } from './../helpers';
5 | import { SharedProps } from './props.type';
6 |
7 | type Props = {
8 | disabledControls?: boolean;
9 | primaryOptions: {
10 | label: string,
11 | value: string
12 | }[];
13 | primaryValue: string;
14 | onPrimaryValueChange: (value: string) => void;
15 | secondaryOptions: {
16 | label: string,
17 | value: string
18 | }[];
19 | secondaryValue: string;
20 | onSecondaryValueChange: (value: string) => void;
21 | label1: string;
22 | label2: string;
23 | } & SharedProps;
24 |
25 | export const SimpleRange = ({
26 | cssClassPrefix = '',
27 | checked = false,
28 | disabled = false,
29 | disabledControls = false,
30 | label1,
31 | label2,
32 | onSelect,
33 | primaryOptions,
34 | primaryValue,
35 | onPrimaryValueChange,
36 | secondaryOptions,
37 | secondaryValue,
38 | onSecondaryValueChange,
39 | segmentId
40 | }: Props) => (
41 |
42 |
43 |
44 |
52 |
53 |
56 | {label1}
57 |
58 |
59 |
60 |
onPrimaryValueChange(e.target.value)}>
65 |
66 | {primaryOptions.map(item => {
67 | return (
68 |
71 | {item.label}
72 |
73 | );
74 | })}
75 |
76 |
77 |
80 | {label2}
81 |
82 |
83 |
onSecondaryValueChange(e.target.value)}>
88 |
89 | {secondaryOptions.map(item => {
90 | return (
91 |
94 | {item.label}
95 |
96 | );
97 | })}
98 |
99 |
100 | );
101 |
--------------------------------------------------------------------------------
/src/lib/unix/index.ts:
--------------------------------------------------------------------------------
1 | export * from './unix';
--------------------------------------------------------------------------------
/src/lib/unix/tabs/day/day.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Segment, getList, getDaysOfWeekCodes, Type, Mode } from '@sbzen/cron-core';
3 |
4 | import { genId, getCssClassPrefix, localizeLabel, genClassName } from './../../../helpers';
5 | import { CronUnixTabProps } from './../shared';
6 |
7 | export const UnixCronDay = ({
8 | service,
9 | session,
10 | localization,
11 | cssClassPrefix
12 | }: CronUnixTabProps) => {
13 | const { common, unix } = localization;
14 | const {
15 | every,
16 | dayOfWeekAnd,
17 | dayOfMonthAnd,
18 | dayOfWeekIncrement,
19 | dayOfMonthIncrement
20 | } = unix.day;
21 | const classPrefix = getCssClassPrefix(cssClassPrefix);
22 | const api = service.getApi(Type.DAY);
23 | const daysOfWeekEvery = getList(Segment.dayOfWeek, true);
24 | const daysOfWeekCodes = getDaysOfWeekCodes();
25 | const daysOfMonth = getList(Segment.dayOfMonth);
26 |
27 | const genEvery = () => (
28 |
29 |
30 | api.selectEvery()} />
38 |
39 |
42 |
43 | {every.label}
44 |
45 |
46 |
47 | );
48 |
49 | const genDayOfWeekIncrement = () => (
50 |
51 |
52 | api.selectDayOfWeekIncrement()} />
60 |
61 |
64 |
65 | {dayOfWeekIncrement.label1}
66 |
67 |
68 |
69 |
api.setDayOfWeekIncrementPrimary(e.target.value)}>
74 |
75 | {daysOfWeekEvery.map(item => {
76 | return (
77 |
80 | {item.value}
81 |
82 | );
83 | })}
84 |
85 |
86 |
89 | {dayOfWeekIncrement.label2}
90 |
91 |
92 | );
93 |
94 | const genDayOfMonthIncrement = () => (
95 |
96 |
97 | api.selectDayOfMonthIncrement()} />
105 |
106 |
109 | {dayOfMonthIncrement.label1}
110 |
111 |
112 |
113 |
api.setDayOfMonthIncrementPrimary(e.target.value)}>
118 |
119 | {daysOfMonth.map(item => {
120 | return (
121 |
124 | {item.value}
125 |
126 | );
127 | })}
128 |
129 |
130 |
133 | {dayOfMonthIncrement.label2}
134 |
135 |
136 | );
137 |
138 | const genDayOfWeekAnd = () => (
139 |
140 |
141 | api.selectDayOfWeekAnd()} />
149 |
150 |
153 | {dayOfWeekAnd.label}
154 |
155 |
156 |
157 |
158 | {daysOfWeekCodes.map(item => {
159 | return (
160 |
164 |
165 |
166 | api.selectDayOfWeekAndValue(item.value)} />
174 |
175 |
178 | {localizeLabel(item.label, common.dayOfWeek)}
179 |
180 |
181 |
182 | );
183 | })}
184 |
185 |
186 | );
187 |
188 | const genDayOfMonthAnd = () => (
189 |
190 |
191 | api.selectDayOfMonthAnd()} />
199 |
200 |
203 | {dayOfMonthAnd.label}
204 |
205 |
206 |
207 |
208 | {daysOfMonth.map(item => {
209 | return (
210 |
214 |
215 |
216 | api.selectDayOfMonthAndValue(item.value)} />
224 |
225 |
228 | {item.label}
229 |
230 |
231 |
232 | );
233 | })}
234 |
235 |
236 | );
237 |
238 | return (
239 |
240 | {genEvery()}
241 | {genDayOfWeekIncrement()}
242 | {genDayOfMonthIncrement()}
243 | {genDayOfWeekAnd()}
244 | {genDayOfMonthAnd()}
245 |
246 | );
247 | };
248 |
--------------------------------------------------------------------------------
/src/lib/unix/tabs/hour/hour.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Segment, getList, Mode, Type } from '@sbzen/cron-core';
3 |
4 | import { SimpleEvery, SimpleAnd, SimpleRange } from './../../../shared';
5 | import { genId, getCssClassPrefix } from './../../../helpers';
6 | import { SimpleIncrement, CronUnixTabProps } from './../shared';
7 |
8 | export const UnixCronHour = ({
9 | service,
10 | session,
11 | localization,
12 | cssClassPrefix
13 | }: CronUnixTabProps) => {
14 | const { every, increment, and, range } = localization.unix.hour;
15 | const classPrefix = getCssClassPrefix(cssClassPrefix);
16 | const api = service.getApi(Type.HOURS);
17 | const hourCodes = getList(Segment.hours, true);
18 | const hoursList = getList(Segment.hours);
19 |
20 | const genEvery = () => (
21 | api.selectEvery()}
27 | label={every.label}/>
28 | );
29 |
30 | const genIncrement = () => (
31 | api.selectIncrement()}
38 | label1={increment.label1}
39 | label2={increment.label2}
40 | primaryOptions={hourCodes}
41 | primaryValue={api.getIncrementPrimaryValue()}
42 | onPrimaryValueChange={api.setIncrementPrimaryValue}/>
43 | );
44 |
45 | const genAnd = () => (
46 | api.selectAnd()}
53 | label={and.label}
54 | onValueChange={api.selectAndValue}
55 | isValueSelected={value => api.isSelectedAndValue(value)}
56 | options={hoursList}/>
57 | );
58 |
59 | const genRange = () => (
60 | api.selectRange()}
66 | disabledControls={api.isRangeControlsDisabled()}
67 | label1={range.label1}
68 | label2={range.label2}
69 | primaryOptions={hoursList}
70 | primaryValue={api.getRangePrimaryValue()}
71 | onPrimaryValueChange={api.setRangePrimaryValue}
72 | secondaryOptions={hoursList}
73 | secondaryValue={api.getRangeSecondaryValue()}
74 | onSecondaryValueChange={api.setRangeSecondaryValue}/>
75 | );
76 |
77 | return (
78 |
79 | {genEvery()}
80 | {genIncrement()}
81 | {genAnd()}
82 | {genRange()}
83 |
84 | );
85 | };
86 |
--------------------------------------------------------------------------------
/src/lib/unix/tabs/index.ts:
--------------------------------------------------------------------------------
1 | export * from './day/day';
2 | export * from './hour/hour';
3 | export * from './minute/minute';
4 | export * from './month/month';
--------------------------------------------------------------------------------
/src/lib/unix/tabs/minute/minute.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Segment, Mode, Type, getList } from '@sbzen/cron-core';
3 |
4 | import { SimpleEvery, SimpleAnd, SimpleRange } from './../../../shared';
5 | import { genId, getCssClassPrefix } from './../../../helpers';
6 | import { SimpleIncrement, CronUnixTabProps } from './../shared';
7 |
8 | export const UnixCronMinute = ({
9 | service,
10 | session,
11 | localization,
12 | cssClassPrefix
13 | }: CronUnixTabProps) => {
14 | const { every, increment, and, range } = localization.unix.minute;
15 | const classPrefix = getCssClassPrefix(cssClassPrefix);
16 | const api = service.getApi(Type.MINUTES);
17 | const minuteCodes = getList(Segment.minutes, true);
18 | const minutesList = getList(Segment.minutes);
19 |
20 | const genEvery = () => (
21 | api.selectEvery()}
27 | label={every.label}/>
28 | );
29 |
30 | const genIncrement = () => (
31 | api.selectIncrement()}
38 | label1={increment.label1}
39 | label2={increment.label2}
40 | primaryOptions={minuteCodes}
41 | primaryValue={api.getIncrementPrimaryValue()}
42 | onPrimaryValueChange={api.setIncrementPrimaryValue}/>
43 | );
44 |
45 | const genAnd = () => (
46 | api.selectAnd()}
53 | label={and.label}
54 | onValueChange={api.selectAndValue}
55 | isValueSelected={value => api.isSelectedAndValue(value)}
56 | options={minutesList}/>
57 | );
58 |
59 | const genRange = () => (
60 | api.selectRange()}
66 | disabledControls={api.isRangeControlsDisabled()}
67 | label1={range.label1}
68 | label2={range.label2}
69 | primaryOptions={minutesList}
70 | primaryValue={api.getRangePrimaryValue()}
71 | onPrimaryValueChange={api.setRangePrimaryValue}
72 | secondaryOptions={minutesList}
73 | secondaryValue={api.getRangeSecondaryValue()}
74 | onSecondaryValueChange={api.setRangeSecondaryValue}/>
75 | );
76 |
77 | return (
78 |
79 | {genEvery()}
80 | {genIncrement()}
81 | {genAnd()}
82 | {genRange()}
83 |
84 | );
85 | };
86 |
--------------------------------------------------------------------------------
/src/lib/unix/tabs/month/month.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Segment, Mode, Type, getMonthCodes, getList } from '@sbzen/cron-core';
3 |
4 | import { genId, getCssClassPrefix, localizeList } from './../../../helpers';
5 | import { SimpleEvery, SimpleAnd, SimpleRange } from './../../../shared';
6 | import { SimpleIncrement, CronUnixTabProps } from './../shared';
7 |
8 | export const UnixCronMonth = ({
9 | service,
10 | localization,
11 | session,
12 | cssClassPrefix
13 | }: CronUnixTabProps) => {
14 | const { common, unix } = localization;
15 | const { every, increment, and, range } = unix.month;
16 | const classPrefix = getCssClassPrefix(cssClassPrefix);
17 | const api = service.getApi(Type.MONTH);
18 | const monthCodes = getMonthCodes();
19 | const monthes = getList(Segment.month);
20 |
21 | const genEvery = () => (
22 | api.selectEvery()}
28 | label={every.label}/>
29 | );
30 |
31 | const genIncrement = () => (
32 | api.selectIncrement()}
39 | label1={increment.label1}
40 | label2={increment.label2}
41 | primaryOptions={monthes.map(({ value }, i) => ({ value, label: i + 1 }))}
42 | primaryValue={api.getIncrementPrimaryValue()}
43 | onPrimaryValueChange={api.setIncrementPrimaryValue}/>
44 | );
45 |
46 | const genAnd = () => (
47 | api.selectAnd()}
55 | label={and.label}
56 | onValueChange={api.selectAndValue}
57 | isValueSelected={value => api.isSelectedAndValue(value)}
58 | options={localizeList(monthCodes, common.month)}/>
59 | );
60 |
61 | const genRange = () => (
62 | api.selectRange()}
68 | disabledControls={api.isRangeControlsDisabled()}
69 | label1={range.label1}
70 | label2={range.label2}
71 | primaryOptions={localizeList(monthes, common.month)}
72 | primaryValue={api.getRangePrimaryValue()}
73 | onPrimaryValueChange={api.setRangePrimaryValue}
74 | secondaryOptions={localizeList(monthes, common.month)}
75 | secondaryValue={api.getRangeSecondaryValue()}
76 | onSecondaryValueChange={api.setRangeSecondaryValue}/>
77 | );
78 |
79 | return (
80 |
81 | {genEvery()}
82 | {genIncrement()}
83 | {genAnd()}
84 | {genRange()}
85 |
86 | );
87 | };
88 |
--------------------------------------------------------------------------------
/src/lib/unix/tabs/shared/increment.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Mode } from '@sbzen/cron-core';
3 |
4 | import { CronBaseProps } from './../../../cron-base-props.type';
5 | import { genClassName } from './../../../helpers';
6 |
7 | type Props = {
8 | checked?: boolean;
9 | disabled?: boolean;
10 | disabledControls?: boolean;
11 | onSelect: () => void;
12 | primaryOptions: {
13 | label: string|number,
14 | value: string
15 | }[];
16 | primaryValue: string;
17 | onPrimaryValueChange: (value: string) => void;
18 | label1: string;
19 | label2: string;
20 | segmentId: string;
21 | } & CronBaseProps;
22 |
23 | export const SimpleIncrement = ({
24 | cssClassPrefix = '',
25 | checked = false,
26 | disabled = false,
27 | disabledControls = false,
28 | label1,
29 | label2,
30 | onSelect,
31 | primaryOptions,
32 | primaryValue,
33 | onPrimaryValueChange,
34 | segmentId
35 | }: Props) => (
36 |
37 |
38 |
46 |
47 |
50 | {label1}
51 |
52 |
53 |
54 |
onPrimaryValueChange(e.target.value)}>
59 |
60 | {primaryOptions.map(item => {
61 | return (
62 |
65 | {item.label}
66 |
67 | );
68 | })}
69 |
70 |
71 |
74 | {label2}
75 |
76 |
77 | );
78 |
--------------------------------------------------------------------------------
/src/lib/unix/tabs/shared/index.ts:
--------------------------------------------------------------------------------
1 | export * from './increment';
2 | export * from './tab-props.type';
3 |
--------------------------------------------------------------------------------
/src/lib/unix/tabs/shared/tab-props.type.ts:
--------------------------------------------------------------------------------
1 | import { CronUnixUIService } from '@sbzen/cron-core';
2 |
3 | import { CronBaseTabProps } from './../../../cron-base-tab-props.type';
4 |
5 | export type CronUnixTabProps = CronBaseTabProps;
6 |
--------------------------------------------------------------------------------
/src/lib/unix/unix.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import {
3 | CronUnixUIService,
4 | UnixType,
5 | Type,
6 | getSegmentsList,
7 | getTypeSegments,
8 | getUnixTypes
9 | } from '@sbzen/cron-core';
10 |
11 | import { getLocalization, genSessionId, genClassName } from './../helpers';
12 | import { CronHostProps } from './../cron-props.type';
13 | import {
14 | UnixCronMinute,
15 | UnixCronHour,
16 | UnixCronMonth,
17 | UnixCronDay
18 | } from './tabs';
19 |
20 | export type ReUnixCronProps = CronHostProps;
21 |
22 | export const ReUnixCron = ({
23 | localization: propLocalization,
24 | hideTabs: propHideTabs,
25 | tabs: propTabs,
26 | value = '',
27 | cssClassPrefix,
28 | activeTab,
29 | disabled,
30 | onTabChange,
31 | onChange
32 | }: ReUnixCronProps) => {
33 | const tabs = (propTabs || getUnixTypes()).filter(t => ![
34 | Type.SECONDS,
35 | Type.YEAR
36 | ].includes(t));
37 | const [tab, setTab] = useState(activeTab || tabs[0]);
38 | const [service] = useState(new CronUnixUIService());
39 | const [renderCount, setRenderCount] = useState(0);
40 | const [session] = useState(genSessionId());
41 | const localization = getLocalization(propLocalization);
42 | const hasTabs = !propHideTabs && !!tabs.length;
43 | const tabProps = {
44 | cssClassPrefix,
45 | localization,
46 | session,
47 | service
48 | };
49 |
50 | useEffect(() => {
51 | const shouldUpdate = !!activeTab && activeTab !== tab;
52 | shouldUpdate && setTab(activeTab);
53 | }, [activeTab]);
54 | useEffect(() => () => service.destroy(), [service]);
55 | useEffect(() => listenChangas());
56 | useEffect(() => service.fillFromExpression(value), [value]);
57 | useEffect(() => service.setDisabled(disabled), [disabled]);
58 |
59 | const listenChangas = () => {
60 | const segments = getSegmentsList();
61 | return service.listen(segments, (_, segment) => {
62 | const shouldApply = getTypeSegments(tab).includes(segment);
63 | if (shouldApply) {
64 | applyChanges();
65 | }
66 | });
67 | };
68 |
69 | const genContent = () => {
70 | if (tab === Type.MINUTES) {
71 | return ;
72 | } else if (tab === Type.HOURS) {
73 | return ;
74 | } else if (tab === Type.MONTH) {
75 | return ;
76 | } else {
77 | return ;
78 | }
79 | };
80 |
81 | const genTabs = (activeTab: UnixType) => {
82 | const className = genClassName(cssClassPrefix, ['nav', 'nav-tabs', 'mb-2'], ['c-tabs']);
83 | return (
84 |
88 |
89 | {tabs.map(t => genTab(t, activeTab))}
90 |
91 | );
92 | };
93 |
94 | const genTab = (tab: UnixType, activeTab: UnixType) => {
95 | const { tabs: tabsLocalization } = localization;
96 | const isActive = activeTab === tab;
97 | const className = genClassName(cssClassPrefix, ['nav-link', isActive ? 'active': ''], [tab, 'c-tab']);
98 | const tabKey = tab.toLowerCase() as keyof typeof tabsLocalization;
99 |
100 | return (
101 |
104 |
105 | changeTab(tab)}>
112 |
113 | {tabsLocalization[tabKey]}
114 |
115 |
116 | );
117 | };
118 |
119 | const changeTab = (tab: UnixType) => {
120 | setTab(tab);
121 | if (onTabChange) {
122 | onTabChange(tab);
123 | }
124 | };
125 |
126 | const applyChanges = () => {
127 | const str = service.toString();
128 | if (str !== value && onChange) {
129 | onChange(str);
130 | }
131 | setRenderCount(renderCount + 1);
132 | };
133 |
134 | return (
135 |
136 | {hasTabs && genTabs(tab)}
137 |
138 |
144 | {genContent()}
145 |
146 |
147 | );
148 | };
149 |
150 | export default ReUnixCron;
151 |
--------------------------------------------------------------------------------
/src/stories/Introduction.stories.mdx:
--------------------------------------------------------------------------------
1 | import { Meta } from '@storybook/addon-docs';
2 | import Code from './assets/code-brackets.svg';
3 | import Colors from './assets/colors.svg';
4 | import Comments from './assets/comments.svg';
5 | import Direction from './assets/direction.svg';
6 | import Flow from './assets/flow.svg';
7 | import Plugin from './assets/plugin.svg';
8 | import Repo from './assets/repo.svg';
9 | import StackAlt from './assets/stackalt.svg';
10 |
11 |
12 |
13 |
116 |
117 | # Welcome to Storybook
118 |
119 | Storybook helps you build UI components in isolation from your app's business logic, data, and context.
120 | That makes it easy to develop hard-to-reach states. Save these UI states as **stories** to revisit during development, testing, or QA.
121 |
122 | Browse example stories now by navigating to them in the sidebar.
123 | View their code in the `stories` directory to learn how they work.
124 | We recommend building UIs with a [**component-driven**](https://componentdriven.org) process starting with atomic components and ending with pages.
125 |
126 | Configure
127 |
128 |
174 |
175 | Learn
176 |
177 |
207 |
208 |
209 | Tip Edit the Markdown in{' '}
210 | stories/Introduction.stories.mdx
211 |
212 |
--------------------------------------------------------------------------------
/src/stories/assets/code-brackets.svg:
--------------------------------------------------------------------------------
1 | illustration/code-brackets
--------------------------------------------------------------------------------
/src/stories/assets/colors.svg:
--------------------------------------------------------------------------------
1 | illustration/colors
--------------------------------------------------------------------------------
/src/stories/assets/comments.svg:
--------------------------------------------------------------------------------
1 | illustration/comments
--------------------------------------------------------------------------------
/src/stories/assets/direction.svg:
--------------------------------------------------------------------------------
1 | illustration/direction
--------------------------------------------------------------------------------
/src/stories/assets/flow.svg:
--------------------------------------------------------------------------------
1 | illustration/flow
--------------------------------------------------------------------------------
/src/stories/assets/plugin.svg:
--------------------------------------------------------------------------------
1 | illustration/plugin
--------------------------------------------------------------------------------
/src/stories/assets/repo.svg:
--------------------------------------------------------------------------------
1 | illustration/repo
--------------------------------------------------------------------------------
/src/stories/assets/stackalt.svg:
--------------------------------------------------------------------------------
1 | illustration/stackalt
--------------------------------------------------------------------------------
/src/stories/quartz-cron.stories.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, Fragment } from 'react';
2 | import { Story, ComponentMeta } from '@storybook/react';
3 |
4 | import { ReQuartzCron, ReQuartzCronProps, Tab } from './../lib';
5 |
6 | const Wrapper = (args: ReQuartzCronProps) => {
7 | const [value, setValue] = useState(args.value);
8 |
9 | useEffect(() => setValue(args.value), [args.value])
10 |
11 | return (
12 |
13 |
14 |
15 |
16 | );
17 | };
18 |
19 | export default {
20 | title: 'ReQuartzCron',
21 | component: ReQuartzCron,
22 | argTypes: {
23 | tabs: {
24 | control: 'inline-check',
25 | options: [
26 | Tab.SECONDS,
27 | Tab.MINUTES,
28 | Tab.HOURS,
29 | Tab.MONTH,
30 | Tab.DAY,
31 | Tab.YEAR
32 | ]
33 | },
34 | activeTab: {
35 | control: 'inline-radio',
36 | options: [
37 | Tab.SECONDS,
38 | Tab.MINUTES,
39 | Tab.HOURS,
40 | Tab.MONTH,
41 | Tab.DAY,
42 | Tab.YEAR
43 | ]
44 | }
45 | }
46 | } as ComponentMeta;
47 |
48 | const Template: Story = args => ;
49 | export const Default = Template.bind({});
50 | Default.args = {
51 | value: '* * * * * * *'
52 | };
53 |
--------------------------------------------------------------------------------
/src/stories/unix-cron.stories.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, Fragment } from 'react';
2 | import { Story, ComponentMeta } from '@storybook/react';
3 |
4 | import { ReUnixCron, ReUnixCronProps, Tab } from './../lib';
5 |
6 | const Wrapper = (args: ReUnixCronProps) => {
7 | const [value, setValue] = useState(args.value);
8 |
9 | useEffect(() => setValue(args.value), [args.value])
10 |
11 | return (
12 |
13 |
14 |
15 |
16 | );
17 | };
18 |
19 | export default {
20 | title: 'ReUnixCron',
21 | component: ReUnixCron,
22 | argTypes: {
23 | tabs: {
24 | control: 'inline-check',
25 | options: [
26 | Tab.MINUTES,
27 | Tab.HOURS,
28 | Tab.MONTH,
29 | Tab.DAY
30 | ]
31 | },
32 | activeTab: {
33 | control: 'inline-radio',
34 | options: [
35 | Tab.MINUTES,
36 | Tab.HOURS,
37 | Tab.MONTH,
38 | Tab.DAY
39 | ]
40 | }
41 | }
42 | } as ComponentMeta;
43 |
44 | const Template: Story = args => ;
45 | export const Default = Template.bind({});
46 | Default.args = {
47 | value: '0 0 1 2,4 *'
48 | };
49 |
--------------------------------------------------------------------------------
/tsconfig.base.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "sourceMap": false,
4 | "declaration": true,
5 | "moduleResolution": "node",
6 | "baseUrl": "./src/lib",
7 | "target": "es2015",
8 | "module": "esnext",
9 | "lib": ["es2017", "dom"],
10 | "resolveJsonModule": true,
11 | "esModuleInterop": true,
12 | "allowSyntheticDefaultImports": true,
13 | "forceConsistentCasingInFileNames": true,
14 | "strict": true,
15 | "jsx": "react",
16 | "noImplicitOverride": true,
17 | "noPropertyAccessFromIndexSignature": true,
18 | "noImplicitReturns": true,
19 | "noFallthroughCasesInSwitch": true,
20 | "paths": {
21 | "@sbzen/re-cron": ["./dist"]
22 | }
23 | },
24 | "exclude": ["node_modules", "dist"]
25 | }
26 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.base.json",
3 | "compilerOptions": {
4 | "outDir": "dist"
5 | },
6 | "include": [
7 | "src/lib/**/*.ts",
8 | "src/lib/**/*.tsx"
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------