├── .npmignore
├── CHANGES.md
├── __mocks__
└── styleMock.js
├── src
├── index.js
├── types
│ ├── Option.js
│ └── CronExpression.js
├── data
│ └── constants.js
├── components
│ ├── components
│ │ ├── Select.js
│ │ ├── DateComponent
│ │ │ ├── index.js
│ │ │ ├── components
│ │ │ │ ├── DayOfMonth.js
│ │ │ │ ├── Month.js
│ │ │ │ └── DayOfWeek.js
│ │ │ ├── DateComponent.test.js
│ │ │ └── DateComponent.js
│ │ ├── TimeInput.js
│ │ └── TimeInput.test.js
│ ├── types
│ │ ├── PresetTabProps.js
│ │ └── PresetTabState.js
│ ├── MultipleSwitcher.test.js
│ ├── Tab.js
│ ├── MultipleSwitcher.js
│ ├── PresetTab.test.js
│ ├── FixedTimeTab.test.js
│ ├── FixedTimeTab.js
│ ├── PresetTab.js
│ ├── PeriodicallyFrameTab.test.js
│ ├── PeriodicallyTab.js
│ ├── PeriodicallyTab.test.js
│ └── PeriodicallyFrameTab.js
├── constants.styl
├── utils
│ ├── utils.test.js
│ └── index.js
├── stories
│ └── CronBuilder.stories.js
├── cron-builder.styl
├── CronBuilder.js
└── Cronbuilder.test.js
├── .gitignore
├── storybook-static
└── favicon.ico
├── postcss.config.js
├── .babelrc
├── .storybook
├── config.js
└── webpack.config.js
├── index.html
├── .flowconfig
├── README.md
├── LICENSE.txt
├── webpack.config.js
├── .eslintrc
├── package.json
└── dist
├── bundle.css
└── bundle.js
/.npmignore:
--------------------------------------------------------------------------------
1 | .idea
2 | coverage
--------------------------------------------------------------------------------
/CHANGES.md:
--------------------------------------------------------------------------------
1 | ## 1.0.1
2 | fixed bug with clear select
--------------------------------------------------------------------------------
/__mocks__/styleMock.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {};
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | export {default} from './CronBuilder'
4 |
--------------------------------------------------------------------------------
/src/types/Option.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | export type Option = {
4 | value: string,
5 | label: string
6 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .storybook/build/storybook_static
2 | package-lock.json
3 | node_modules
4 | coverage
5 | *.log
6 | .idea
--------------------------------------------------------------------------------
/storybook-static/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/one-more/react-cron-builder/HEAD/storybook-static/favicon.ico
--------------------------------------------------------------------------------
/src/data/constants.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | export const MINUTES = 'MINUTES';
4 | export const HOURS = 'HOURS';
5 | export const EVERY = '*';
6 |
--------------------------------------------------------------------------------
/src/components/components/Select.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | import 'react-select/dist/react-select.css'
4 |
5 | export {default} from 'react-select'
6 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [
3 | require('autoprefixer')({
4 | browsers: ['> 5%', 'IE > 9'],
5 | cascade: false
6 | })
7 | ]
8 | };
9 |
--------------------------------------------------------------------------------
/src/types/CronExpression.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | export type CronExpression = {
4 | minutes: any,
5 | hours: any,
6 | dayOfWeek: any,
7 | dayOfMonth: any,
8 | month: any
9 | }
10 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [ "es2015", "react" ],
3 | "plugins": [
4 | "transform-decorators-legacy",
5 | "transform-object-rest-spread",
6 | "transform-class-properties"
7 | ]
8 | }
--------------------------------------------------------------------------------
/src/components/types/PresetTabProps.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | import type {CronExpression} from 'types/CronExpression'
4 |
5 | export type PresetTabProps = {
6 | styleNameFactory: any,
7 | expression: CronExpression
8 | }
9 |
--------------------------------------------------------------------------------
/src/constants.styl:
--------------------------------------------------------------------------------
1 | $blue=#3CAED6
2 | $darkBlue=#289CC7
3 |
4 | $darkGrey=#818181
5 | $grey=#cecece
6 | $grey100=#d3d3d3
7 | $lightGrey=#e6e6e6
8 |
9 | $white=#fff
10 |
11 | $black=#303741
12 |
13 | $button-bg=linear-gradient(to bottom, $white, $lightGrey)
--------------------------------------------------------------------------------
/src/components/components/DateComponent/index.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | export {default} from './DateComponent'
4 | export {default as DayOfWeek} from './components/DayOfWeek'
5 | export {default as DayOfMonth} from './components/DayOfMonth'
6 | export {default as Month} from './components/Month'
7 |
--------------------------------------------------------------------------------
/.storybook/config.js:
--------------------------------------------------------------------------------
1 | import { configure } from '@storybook/react';
2 |
3 | // automatically import all files ending in *.stories.js
4 | const req = require.context('../src/stories', true, /.stories.js$/);
5 | function loadStories() {
6 | req.keys().forEach(filename => req(filename));
7 | }
8 |
9 | configure(loadStories, module);
10 |
--------------------------------------------------------------------------------
/src/components/types/PresetTabState.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | export type PresetTabState = {
4 | minutes: any,
5 | hours: any,
6 | dayOfWeek: any,
7 | dayOfMonth: any,
8 | month: any,
9 | activeTime: string,
10 | minutesMultiple: boolean,
11 | hoursMultiple: boolean,
12 | hoursFrom?: string,
13 | hoursTo?: string
14 | }
15 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Title
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.flowconfig:
--------------------------------------------------------------------------------
1 | [options]
2 | esproposal.decorators=ignore
3 | unsafe.enable_getters_and_setters=true
4 |
5 | module.system.node.resolve_dirname=src
6 | module.system.node.resolve_dirname=node_modules
7 |
8 | module.name_mapper='^.*\.styl$' -> 'css-module-flow'
9 |
10 | module.ignore_non_literal_requires=true
11 |
12 | suppress_comment=\\(.\\|\n\\)*\\$FlowIgnore
13 |
14 | [ignore]
15 | .*/stylelint/.*
16 |
--------------------------------------------------------------------------------
/src/components/MultipleSwitcher.test.js:
--------------------------------------------------------------------------------
1 | import {mount} from 'enzyme'
2 | import React from 'react'
3 | import MultipleSwitcher from './MultipleSwitcher'
4 | import Tab from './Tab'
5 |
6 | describe('MultipleSwitcher', () => {
7 | const styleNameFactory = jest.fn();
8 |
9 | it('initial rendering', () => {
10 | const wrapper = mount();
13 | expect(wrapper.find(Tab)).toHaveLength(2)
14 | })
15 | });
16 |
--------------------------------------------------------------------------------
/src/components/components/DateComponent/components/DayOfMonth.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | import {PureComponent} from 'react'
4 | import {toOptions} from 'utils'
5 | import range from 'lodash/range'
6 |
7 | const options = [
8 | {
9 | label: 'every month day',
10 | value: '*'
11 | }
12 | ].concat(toOptions(range(1, 32)));
13 |
14 | export default class DayOfMonth extends PureComponent {
15 | static getOptions() {
16 | return options
17 | }
18 |
19 | static className: string = 'DayOfMonth';
20 | }
21 |
--------------------------------------------------------------------------------
/src/utils/utils.test.js:
--------------------------------------------------------------------------------
1 | import {MINUTES, HOURS} from 'data/constants'
2 | import {ensureMultiple, toggleDateType} from './index'
3 |
4 | describe('utils', () => {
5 | it('ensure multiple', () => {
6 | expect(ensureMultiple([1], false)).toEqual(1);
7 | expect(ensureMultiple([1], true)).toEqual([1]);
8 | expect(ensureMultiple(1, true)).toEqual([1]);
9 | expect(ensureMultiple(1, false)).toEqual(1);
10 | });
11 |
12 | it('toggleDateType', () => {
13 | expect(toggleDateType(MINUTES)).toEqual(HOURS);
14 | expect(toggleDateType(HOURS)).toEqual(MINUTES);
15 | })
16 | });
17 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React Cron Builder
2 | React component to build [cron](https://ru.wikipedia.org/wiki/Cron) expression
3 |
4 | ## installation
5 | ```` bash
6 | npm install --save react-cron-builder
7 | ````
8 | ## demo
9 | [Live demo](https://one-more.github.io/react-cron-builder/)
10 |
11 | ## usage
12 | ```` ecmascript 6
13 | import CronBuilder from 'react-cron-builder
14 | import 'react-cron-builder/dist/bundle.css'
15 |
16 |
21 | ````
22 |
23 | component was inspired by [this util](https://abunchofutils.com/u/computing/cron-format-helper/)
--------------------------------------------------------------------------------
/src/components/components/DateComponent/components/Month.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | import {PureComponent} from 'react'
4 |
5 | const monthOptions = [
6 | 'January', 'February', 'March', 'April',
7 | 'May', 'June', 'July', 'August', 'September',
8 | 'October', 'November', 'December'
9 | ].map((month: string, i: number) => ({
10 | label: month,
11 | value: String(i + 1)
12 | }));
13 |
14 | const options = [
15 | {
16 | label: 'every month',
17 | value: '*'
18 | }
19 | ].concat(monthOptions);
20 |
21 | export default class Month extends PureComponent {
22 | static getOptions() {
23 | return options
24 | }
25 |
26 | static className: string = 'Month';
27 | }
28 |
--------------------------------------------------------------------------------
/src/stories/CronBuilder.stories.js:
--------------------------------------------------------------------------------
1 | import {storiesOf, action} from '@storybook/react'
2 | import React from 'react'
3 | import CronBuilder from '../CronBuilder'
4 |
5 | storiesOf('CronBuilder', module)
6 | .add('default', () => )
9 | .add('do not show result', () => )
13 | .add('with predefined expression', () => )
17 | .add('with predefined expression time frame', () => );
21 |
--------------------------------------------------------------------------------
/src/components/Tab.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | import React, {PureComponent} from 'react'
4 | import noop from 'lodash/noop'
5 |
6 | type Props = {
7 | children?: any,
8 | isActive: boolean,
9 | styleNameFactory: any,
10 | onClick: Function
11 | };
12 |
13 | export default class Tab extends PureComponent {
14 | static defaultProps = {
15 | children: null,
16 | onClick: noop
17 | };
18 |
19 | props: Props;
20 |
21 | render() {
22 | const {isActive, children, styleNameFactory, onClick} = this.props;
23 | return (
24 |
31 | )
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/components/components/DateComponent/components/DayOfWeek.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | import {PureComponent} from 'react'
4 |
5 | const weekDaysOptions = [
6 | 'Mondays', 'Tuesdays', 'Wednesdays',
7 | 'Thursdays', 'Fridays', 'Saturdays',
8 | 'Sundays'
9 | ].map((day: string, i: number) => ({
10 | label: day,
11 | value: String(i + 1)
12 | }));
13 |
14 | const options = [
15 | {
16 | label: 'every day',
17 | value: '*'
18 | },
19 | {
20 | label: 'Mondays to Fridays',
21 | value: '1-5'
22 | },
23 | {
24 | label: 'Saturdays and Sundays',
25 | value: '6-7'
26 | }
27 | ].concat(weekDaysOptions);
28 |
29 | export default class DayOfWeek extends PureComponent {
30 | static getOptions() {
31 | return options
32 | }
33 |
34 | static className: string = 'DayOfWeek';
35 | }
36 |
--------------------------------------------------------------------------------
/src/components/components/TimeInput.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | import React, {PureComponent} from 'react'
4 | import type {Option} from 'types/Option'
5 | import {parseTimeValue, getValues, getValue} from 'utils'
6 | import Select from './Select'
7 |
8 | type Props = {
9 | value: any,
10 | options: Array