mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-24 09:28:31 +00:00
Feature: Calendar widget 🗓 (#1368)
* Insert required boilerplate code for Calendar widget * Display basic calendar * Display events on calendar widget * Pass JS date object as calendar default event date * Add resource scheduling to Calendar widget * Add icon for Calendar widget * Allow configuration of views and default view for calendar * Add onEventSelect event to Calendar widget * Accept date as string for Calendar * Option to disable/enable toolbar in Calendar * Add default date to Calendar * Add support for setting color of calendar events * Set calendar cell size to 50px * Allow spacious and compact cell sizes for Calendar * Add support for "select slots" event for calendar * Add support for custom event tooltip for Calendar * Add support to not highlight today and now in Calendar * Add visible border for Calendar events * Set 14px font size for calendar toolbar * Add dark mode styles for calendar * Make calendar view mode controllable with logic * Add documentation for calendar widget * Add additional documentation for calendar events * Expose default view instead of view for calendar * Add documentation for changes in calendar * Style updates to calendar * Increase padding for calendar events
This commit is contained in:
parent
a6f99f6fba
commit
8bbbbfc869
13 changed files with 584 additions and 1 deletions
109
docs/docs/widgets/calendar.md
Normal file
109
docs/docs/widgets/calendar.md
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
---
|
||||
sidebar_position: 22
|
||||
---
|
||||
|
||||
# Calendar
|
||||
Calendar widget comes with the following features:
|
||||
- Day, month and week level views
|
||||
- Events
|
||||
- Resource scheduling
|
||||
|
||||
<img class="screenshot-full" src="/img/widgets/calendar/calendar1.png" alt="ToolJet - Widget Reference - Calendar" height="600"/>
|
||||
|
||||
### Properties
|
||||
|
||||
#### Date format
|
||||
Determines the format in which any date passed to the calendar via any of the properties will be parsed.
|
||||
It also determines the format in which any date made available by the calendar via exposed variables will be displayed.
|
||||
It uses the date format conventions of [moment.js](https://momentjs.com/).
|
||||
#### Default date
|
||||
Determines the date on which the calendar's view will be centered on.
|
||||
If the calendar is on `month` view, it will show the month on which this date exists.
|
||||
If the calendar is on `week` view, it will show the week on which this date exists.
|
||||
This property needs to be formatted using the `Date format` property which is configurable on the inspector.
|
||||
#### Events
|
||||
`Events` property should contain an array of objects, each of which describes the events that the calendar needs to display.
|
||||
|
||||
Assuming that you set the date format to `MM-DD-YYYY HH:mm:ss A Z`, setting the `Events` property to the following code snippet will display an event titled `Sample Event` at the first hour of this day, as displayed in the image of calendar at the beginning of this page.
|
||||
|
||||
```javascript
|
||||
{{[
|
||||
{
|
||||
title: 'Sample event',
|
||||
start: `${moment().startOf('day').format('MM-DD-YYYY HH:mm:ss A Z')}`,
|
||||
end: `${moment().endOf('day').format('MM-DD-YYYY HH:mm:ss A Z')}`,
|
||||
allDay: false,
|
||||
tooltip: 'Sample event',
|
||||
color: 'lightgreen',
|
||||
}
|
||||
]}}
|
||||
```
|
||||
|
||||
##### Event object properties
|
||||
|
||||
| Name | Description |
|
||||
|------|-------------|
|
||||
| title | Title of the event |
|
||||
| start | The date(and time) on which this event begins. Needs to be formatted in the `Date format` you've supplied |
|
||||
| end | The date(and time) on which this event ends. Needs to be formatted in the `Date format` you've supplied |
|
||||
| allDay | Optional. Qualifies the event as an 'All day event', which will pin it to date headers on `day` and `week` level views |
|
||||
| tooltip | Tooltip which will be display when the user hovers over the event |
|
||||
| color | Background color of the event, any css supported color name or hex code can be used |
|
||||
| textOrientation | Optional. If it is set to `vertical`, the title of the event will be oriented vertically. |
|
||||
| resourceId | Applicable only if you're using resource scheduling. This is the id of the resource to which this event correspond to. |
|
||||
|
||||
You may supply any other additional property to the event(s). These additional properties will available to you when the calendar widget
|
||||
exposes any of the events via its exposed variables.
|
||||
|
||||
#### Resources
|
||||
|
||||
Specifying resources will make the calendar categorize `week` view and `day` view for each of the resources specified.
|
||||
|
||||
For example, to categorize week/day view into for three rooms, we specify `resources` this way:
|
||||
|
||||
```javascript
|
||||
{{
|
||||
[
|
||||
{resourceId: 1, title: 'Room A'},
|
||||
{resourceId: 2, title: 'Room B'},
|
||||
{resourceId: 3, title: 'Room C'},
|
||||
]
|
||||
}}
|
||||
```
|
||||
|
||||
If we specify the `resourceId` of any of the events as `1`, then that event will be assigned to `Room A`, generating the following calendar, assuming that we've set the view to `day` and are viewing the day on which this event exists.
|
||||
|
||||
<img class="screenshot-full" src="/img/widgets/calendar/calendar-resource.png" alt="ToolJet - Widget Reference - Calendar Resources" height="600"/>
|
||||
|
||||
#### Default view
|
||||
|
||||
Determines whether the calendar would display a `day`, a `week` or a `month`.
|
||||
Setting this property to anything other than these values will make the calendar default to `month` view.
|
||||
|
||||
#### Show toolbar
|
||||
|
||||
Determines whether the calendar toolbar should be displayed or not.
|
||||
|
||||
#### Show view switcher
|
||||
|
||||
Determinues whether the calendar's buttons that allow user to switch between `month`, `week` and `day` level views will be displayed.
|
||||
### Styles
|
||||
#### Cell size in views classified by resource
|
||||
|
||||
When `resources` are specified, the calendar could take up quite a lot of horizontal space, making the horizontal scroll bar of calendar having to be relied upon all the time.
|
||||
|
||||
If we set this property to `compact`, the cell sizes will be smaller in `week` and `day` views.
|
||||
|
||||
### Events
|
||||
|
||||
#### On Event selected
|
||||
|
||||
This event is fired when the user clicks on a calendar event.
|
||||
|
||||
Last selected event is exposed as `selectedEvent`.
|
||||
|
||||
#### on Slot selected
|
||||
|
||||
This event is fired when the user either clicks on an calendar slot(empty cell or empty space of a cell with event) or when they click and drag to select multiple slots.
|
||||
|
||||
Last selected slot(s) are exposed as `selectedSlots`.
|
||||
BIN
docs/static/img/widgets/calendar/calendar-day.png
vendored
Normal file
BIN
docs/static/img/widgets/calendar/calendar-day.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 39 KiB |
BIN
docs/static/img/widgets/calendar/calendar-resource.png
vendored
Normal file
BIN
docs/static/img/widgets/calendar/calendar-resource.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 49 KiB |
BIN
docs/static/img/widgets/calendar/calendar-week.png
vendored
Normal file
BIN
docs/static/img/widgets/calendar/calendar-week.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 68 KiB |
BIN
docs/static/img/widgets/calendar/calendar1.png
vendored
Normal file
BIN
docs/static/img/widgets/calendar/calendar1.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 53 KiB |
69
frontend/assets/images/icons/widgets/calendar.svg
Normal file
69
frontend/assets/images/icons/widgets/calendar.svg
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 470 470" style="enable-background:new 0 0 470 470;" xml:space="preserve">
|
||||
<g>
|
||||
<path d="M462.5,425H7.5c-4.142,0-7.5,3.358-7.5,7.5s3.358,7.5,7.5,7.5h455c4.143,0,7.5-3.358,7.5-7.5S466.643,425,462.5,425z"/>
|
||||
<path d="M462.5,455H7.5c-4.142,0-7.5,3.358-7.5,7.5s3.358,7.5,7.5,7.5h455c4.143,0,7.5-3.358,7.5-7.5S466.643,455,462.5,455z"/>
|
||||
<path d="M462.5,30h-25v-7.5C437.5,10.093,427.406,0,415,0s-22.5,10.093-22.5,22.5V30h-75v-7.5C317.5,10.093,307.406,0,295,0
|
||||
s-22.5,10.093-22.5,22.5V30h-75v-7.5C197.5,10.093,187.407,0,175,0s-22.5,10.093-22.5,22.5V30h-75v-7.5C77.5,10.093,67.407,0,55,0
|
||||
S32.5,10.093,32.5,22.5V30h-25C3.358,30,0,33.358,0,37.5v365c0,4.142,3.358,7.5,7.5,7.5h455c4.143,0,7.5-3.358,7.5-7.5v-365
|
||||
C470,33.358,466.643,30,462.5,30z M407.5,22.5c0-4.136,3.364-7.5,7.5-7.5s7.5,3.364,7.5,7.5v30c0,4.136-3.364,7.5-7.5,7.5
|
||||
s-7.5-3.364-7.5-7.5V22.5z M287.5,22.5c0-4.136,3.364-7.5,7.5-7.5s7.5,3.364,7.5,7.5v30c0,4.136-3.364,7.5-7.5,7.5
|
||||
s-7.5-3.364-7.5-7.5V22.5z M167.5,22.5c0-4.136,3.364-7.5,7.5-7.5s7.5,3.364,7.5,7.5v30c0,4.136-3.364,7.5-7.5,7.5
|
||||
s-7.5-3.364-7.5-7.5V22.5z M47.5,22.5c0-4.136,3.364-7.5,7.5-7.5s7.5,3.364,7.5,7.5v30c0,4.136-3.364,7.5-7.5,7.5
|
||||
s-7.5-3.364-7.5-7.5V22.5z M32.5,45v7.5C32.5,64.907,42.593,75,55,75s22.5-10.093,22.5-22.5V45h75v7.5
|
||||
c0,12.407,10.093,22.5,22.5,22.5s22.5-10.093,22.5-22.5V45h75v7.5c0,12.407,10.094,22.5,22.5,22.5s22.5-10.093,22.5-22.5V45h75v7.5
|
||||
c0,12.407,10.094,22.5,22.5,22.5s22.5-10.093,22.5-22.5V45H455v77.3H15V45H32.5z M15,395V137.3h440V395H15z"/>
|
||||
<path d="M412,226.8h-30c-4.143,0-7.5,3.358-7.5,7.5s3.357,7.5,7.5,7.5h30c4.143,0,7.5-3.358,7.5-7.5S416.143,226.8,412,226.8z"/>
|
||||
<path d="M331,226.8h-30c-4.143,0-7.5,3.358-7.5,7.5s3.357,7.5,7.5,7.5h30c4.143,0,7.5-3.358,7.5-7.5S335.143,226.8,331,226.8z"/>
|
||||
<path d="M250,226.8h-30c-4.142,0-7.5,3.358-7.5,7.5s3.358,7.5,7.5,7.5h30c4.143,0,7.5-3.358,7.5-7.5S254.143,226.8,250,226.8z"/>
|
||||
<path d="M169,226.8h-30c-4.142,0-7.5,3.358-7.5,7.5s3.358,7.5,7.5,7.5h30c4.142,0,7.5-3.358,7.5-7.5S173.142,226.8,169,226.8z"/>
|
||||
<path d="M88,226.8H58c-4.142,0-7.5,3.358-7.5,7.5s3.358,7.5,7.5,7.5h30c4.142,0,7.5-3.358,7.5-7.5S92.142,226.8,88,226.8z"/>
|
||||
<path d="M331,280.8h-30c-4.143,0-7.5,3.358-7.5,7.5s3.357,7.5,7.5,7.5h30c4.143,0,7.5-3.358,7.5-7.5S335.143,280.8,331,280.8z"/>
|
||||
<path d="M250,280.8h-30c-4.142,0-7.5,3.358-7.5,7.5s3.358,7.5,7.5,7.5h30c4.143,0,7.5-3.358,7.5-7.5S254.143,280.8,250,280.8z"/>
|
||||
<path d="M169,280.8h-30c-4.142,0-7.5,3.358-7.5,7.5s3.358,7.5,7.5,7.5h30c4.142,0,7.5-3.358,7.5-7.5S173.142,280.8,169,280.8z"/>
|
||||
<path d="M88,280.8H58c-4.142,0-7.5,3.358-7.5,7.5s3.358,7.5,7.5,7.5h30c4.142,0,7.5-3.358,7.5-7.5S92.142,280.8,88,280.8z"/>
|
||||
<path d="M331,334.8h-30c-4.143,0-7.5,3.358-7.5,7.5s3.357,7.5,7.5,7.5h30c4.143,0,7.5-3.358,7.5-7.5S335.143,334.8,331,334.8z"/>
|
||||
<path d="M412,280.8h-30c-4.143,0-7.5,3.358-7.5,7.5s3.357,7.5,7.5,7.5h30c4.143,0,7.5-3.358,7.5-7.5S416.143,280.8,412,280.8z"/>
|
||||
<path d="M412,334.8h-30c-4.143,0-7.5,3.358-7.5,7.5s3.357,7.5,7.5,7.5h30c4.143,0,7.5-3.358,7.5-7.5S416.143,334.8,412,334.8z"/>
|
||||
<path d="M250,334.8h-30c-4.142,0-7.5,3.358-7.5,7.5s3.358,7.5,7.5,7.5h30c4.143,0,7.5-3.358,7.5-7.5S254.143,334.8,250,334.8z"/>
|
||||
<path d="M169,334.8h-30c-4.142,0-7.5,3.358-7.5,7.5s3.358,7.5,7.5,7.5h30c4.142,0,7.5-3.358,7.5-7.5S173.142,334.8,169,334.8z"/>
|
||||
<path d="M88,334.8H58c-4.142,0-7.5,3.358-7.5,7.5s3.358,7.5,7.5,7.5h30c4.142,0,7.5-3.358,7.5-7.5S92.142,334.8,88,334.8z"/>
|
||||
<path d="M412,172.8h-30c-4.143,0-7.5,3.358-7.5,7.5s3.357,7.5,7.5,7.5h30c4.143,0,7.5-3.358,7.5-7.5S416.143,172.8,412,172.8z"/>
|
||||
<path d="M331,172.8h-30c-4.143,0-7.5,3.358-7.5,7.5s3.357,7.5,7.5,7.5h30c4.143,0,7.5-3.358,7.5-7.5S335.143,172.8,331,172.8z"/>
|
||||
<path d="M250,172.8h-30c-4.142,0-7.5,3.358-7.5,7.5s3.358,7.5,7.5,7.5h30c4.143,0,7.5-3.358,7.5-7.5S254.143,172.8,250,172.8z"/>
|
||||
<path d="M169,172.8h-30c-4.142,0-7.5,3.358-7.5,7.5s3.358,7.5,7.5,7.5h30c4.142,0,7.5-3.358,7.5-7.5S173.142,172.8,169,172.8z"/>
|
||||
<path d="M88,172.8H58c-4.142,0-7.5,3.358-7.5,7.5s3.358,7.5,7.5,7.5h30c4.142,0,7.5-3.358,7.5-7.5S92.142,172.8,88,172.8z"/>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.4 KiB |
97
frontend/package-lock.json
generated
97
frontend/package-lock.json
generated
|
|
@ -41,6 +41,7 @@
|
|||
"plotly.js-basic-dist-min": "^1.58.4",
|
||||
"query-string": "^6.13.6",
|
||||
"react": "^16.14.0",
|
||||
"react-big-calendar": "^0.38.0",
|
||||
"react-bootstrap": "^1.5.2",
|
||||
"react-color": "^2.19.3",
|
||||
"react-copy-to-clipboard": "^5.0.3",
|
||||
|
|
@ -7594,6 +7595,11 @@
|
|||
"webidl-conversions": "^4.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/date-arithmetic": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/date-arithmetic/-/date-arithmetic-4.1.0.tgz",
|
||||
"integrity": "sha512-QWxYLR5P/6GStZcdem+V1xoto6DMadYWpMXU82ES3/RfR3Wdwr3D0+be7mgOJ+Ov0G9D5Dmb9T17sNLQYj9XOg=="
|
||||
},
|
||||
"node_modules/date-fns": {
|
||||
"version": "1.30.1",
|
||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz",
|
||||
|
|
@ -14233,6 +14239,11 @@
|
|||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/memoize-one": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz",
|
||||
"integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q=="
|
||||
},
|
||||
"node_modules/memory-fs": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
|
||||
|
|
@ -17404,6 +17415,47 @@
|
|||
"pure-color": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-big-calendar": {
|
||||
"version": "0.38.0",
|
||||
"resolved": "https://registry.npmjs.org/react-big-calendar/-/react-big-calendar-0.38.0.tgz",
|
||||
"integrity": "sha512-eoVkt9gTo+f1HBL09+o7dYLxp6QxHv52fcn50P5PfaWp3S98uGLQqoqsvghT85koMKvGfDVa5V0+J7yHcaF07Q==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.1.5",
|
||||
"clsx": "^1.0.4",
|
||||
"date-arithmetic": "^4.1.0",
|
||||
"dom-helpers": "^5.1.0",
|
||||
"invariant": "^2.2.4",
|
||||
"lodash": "^4.17.11",
|
||||
"lodash-es": "^4.17.11",
|
||||
"memoize-one": "^5.1.1",
|
||||
"prop-types": "^15.7.2",
|
||||
"react-overlays": "^4.1.1",
|
||||
"uncontrollable": "^7.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.6.1 || ^17",
|
||||
"react-dom": "^16.6.1 || ^17"
|
||||
}
|
||||
},
|
||||
"node_modules/react-big-calendar/node_modules/react-overlays": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-4.1.1.tgz",
|
||||
"integrity": "sha512-WtJifh081e6M24KnvTQoNjQEpz7HoLxqt8TwZM7LOYIkYJ8i/Ly1Xi7RVte87ZVnmqQ4PFaFiNHZhSINPSpdBQ==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.1",
|
||||
"@popperjs/core": "^2.5.3",
|
||||
"@restart/hooks": "^0.3.25",
|
||||
"@types/warning": "^3.0.0",
|
||||
"dom-helpers": "^5.2.0",
|
||||
"prop-types": "^15.7.2",
|
||||
"uncontrollable": "^7.0.0",
|
||||
"warning": "^4.0.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.3.0",
|
||||
"react-dom": ">=16.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-bootstrap": {
|
||||
"version": "1.5.2",
|
||||
"resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-1.5.2.tgz",
|
||||
|
|
@ -30304,6 +30356,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"date-arithmetic": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/date-arithmetic/-/date-arithmetic-4.1.0.tgz",
|
||||
"integrity": "sha512-QWxYLR5P/6GStZcdem+V1xoto6DMadYWpMXU82ES3/RfR3Wdwr3D0+be7mgOJ+Ov0G9D5Dmb9T17sNLQYj9XOg=="
|
||||
},
|
||||
"date-fns": {
|
||||
"version": "1.30.1",
|
||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz",
|
||||
|
|
@ -35470,6 +35527,11 @@
|
|||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
|
||||
},
|
||||
"memoize-one": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz",
|
||||
"integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q=="
|
||||
},
|
||||
"memory-fs": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
|
||||
|
|
@ -38058,6 +38120,41 @@
|
|||
"pure-color": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"react-big-calendar": {
|
||||
"version": "0.38.0",
|
||||
"resolved": "https://registry.npmjs.org/react-big-calendar/-/react-big-calendar-0.38.0.tgz",
|
||||
"integrity": "sha512-eoVkt9gTo+f1HBL09+o7dYLxp6QxHv52fcn50P5PfaWp3S98uGLQqoqsvghT85koMKvGfDVa5V0+J7yHcaF07Q==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.1.5",
|
||||
"clsx": "^1.0.4",
|
||||
"date-arithmetic": "^4.1.0",
|
||||
"dom-helpers": "^5.1.0",
|
||||
"invariant": "^2.2.4",
|
||||
"lodash": "^4.17.11",
|
||||
"lodash-es": "^4.17.11",
|
||||
"memoize-one": "^5.1.1",
|
||||
"prop-types": "^15.7.2",
|
||||
"react-overlays": "^4.1.1",
|
||||
"uncontrollable": "^7.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"react-overlays": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-4.1.1.tgz",
|
||||
"integrity": "sha512-WtJifh081e6M24KnvTQoNjQEpz7HoLxqt8TwZM7LOYIkYJ8i/Ly1Xi7RVte87ZVnmqQ4PFaFiNHZhSINPSpdBQ==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.12.1",
|
||||
"@popperjs/core": "^2.5.3",
|
||||
"@restart/hooks": "^0.3.25",
|
||||
"@types/warning": "^3.0.0",
|
||||
"dom-helpers": "^5.2.0",
|
||||
"prop-types": "^15.7.2",
|
||||
"uncontrollable": "^7.0.0",
|
||||
"warning": "^4.0.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-bootstrap": {
|
||||
"version": "1.5.2",
|
||||
"resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-1.5.2.tgz",
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
"plotly.js-basic-dist-min": "^1.58.4",
|
||||
"query-string": "^6.13.6",
|
||||
"react": "^16.14.0",
|
||||
"react-big-calendar": "^0.38.0",
|
||||
"react-bootstrap": "^1.5.2",
|
||||
"react-color": "^2.19.3",
|
||||
"react-copy-to-clipboard": "^5.0.3",
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import { StarRating } from './Components/StarRating';
|
|||
import { Divider } from './Components/Divider';
|
||||
import { FilePicker } from './Components/FilePicker';
|
||||
import { PasswordInput } from './Components/PasswordInput';
|
||||
import { Calendar } from './Components/Calendar';
|
||||
import { renderTooltip } from '../_helpers/appUtils';
|
||||
import OverlayTrigger from 'react-bootstrap/OverlayTrigger';
|
||||
import '@/_styles/custom.scss';
|
||||
|
|
@ -54,6 +55,7 @@ const AllComponents = {
|
|||
Divider,
|
||||
FilePicker,
|
||||
PasswordInput,
|
||||
Calendar,
|
||||
};
|
||||
|
||||
export const Box = function Box({
|
||||
|
|
|
|||
84
frontend/src/Editor/Components/Calendar.jsx
Normal file
84
frontend/src/Editor/Components/Calendar.jsx
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
import React from 'react';
|
||||
import { Calendar as ReactCalendar, momentLocalizer } from 'react-big-calendar';
|
||||
import moment from 'moment';
|
||||
import 'react-big-calendar/lib/css/react-big-calendar.css';
|
||||
|
||||
const localizer = momentLocalizer(moment);
|
||||
|
||||
const prepareEvent = (event, dateFormat) => ({
|
||||
...event,
|
||||
start: moment(event.start, dateFormat).toDate(),
|
||||
end: moment(event.end, dateFormat).toDate(),
|
||||
});
|
||||
|
||||
const parseDate = (date, dateFormat) => moment(date, dateFormat).toDate();
|
||||
|
||||
const allowedCalendarViews = ['month', 'week', 'day'];
|
||||
|
||||
export const Calendar = function ({ height, width, properties, styles, fireEvent, darkMode }) {
|
||||
const style = { height, width };
|
||||
const resourcesParam = properties.resources?.length === 0 ? {} : { resources: properties.resources };
|
||||
|
||||
const events = properties.events ? properties.events.map((event) => prepareEvent(event, properties.dateFormat)) : [];
|
||||
const defaultDate = parseDate(properties.defaultDate, properties.dateFormat);
|
||||
|
||||
const eventPropGetter = (event) => {
|
||||
const backgroundColor = event.color;
|
||||
const textStyle =
|
||||
event.textOrientation === 'vertical' ? { writingMode: 'vertical-rl', textOrientation: 'mixed' } : {};
|
||||
const style = { backgroundColor, ...textStyle, padding: 3, paddingLeft: 5, paddingRight: 5 };
|
||||
|
||||
return { style };
|
||||
};
|
||||
|
||||
const slotSelectHandler = (calendarSlots) => {
|
||||
const { slots, start, end, resourceId, action } = calendarSlots;
|
||||
const formattedSlots = slots.map((slot) => moment(slot).format(properties.dateFormat));
|
||||
const formattedStart = moment(start).format(properties.dateFormat);
|
||||
const formattedEnd = moment(end).format(properties.dateFormat);
|
||||
|
||||
const selectedSlots = {
|
||||
slots: formattedSlots,
|
||||
start: formattedStart,
|
||||
end: formattedEnd,
|
||||
resourceId,
|
||||
action,
|
||||
};
|
||||
|
||||
fireEvent('onCalendarSlotSelect', { selectedSlots });
|
||||
};
|
||||
|
||||
const defaultView = allowedCalendarViews.includes(properties.defaultView)
|
||||
? properties.defaultView
|
||||
: allowedCalendarViews[0];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ReactCalendar
|
||||
className={`calendar-widget
|
||||
${darkMode ? 'dark-mode' : ''}
|
||||
${styles.cellSizeInViewsClassifiedByResource}
|
||||
${properties.highlightToday ? '' : 'dont-highlight-today'}
|
||||
${properties.displayViewSwitcher ? '' : 'hide-view-switcher'}`}
|
||||
localizer={localizer}
|
||||
defaultDate={defaultDate}
|
||||
events={events}
|
||||
startAccessor="start"
|
||||
endAccessor="end"
|
||||
style={style}
|
||||
views={allowedCalendarViews}
|
||||
defaultView={defaultView}
|
||||
{...resourcesParam}
|
||||
resourceIdAccessor="resourceId"
|
||||
resourceTitleAccessor="title"
|
||||
onSelectEvent={(calendarEvent) => fireEvent('onCalendarEventSelect', { calendarEvent })}
|
||||
selectable={true}
|
||||
onSelectSlot={slotSelectHandler}
|
||||
toolbar={properties.displayToolbar}
|
||||
eventPropGetter={eventPropGetter}
|
||||
tooltipAccessor="tooltip"
|
||||
popup={true}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -1003,7 +1003,7 @@ export const componentTypes = [
|
|||
canSearch: {
|
||||
value: `{{true}}`,
|
||||
},
|
||||
addNewMarkers : {value:`{{true}}`},
|
||||
addNewMarkers: { value: `{{true}}` },
|
||||
},
|
||||
events: [],
|
||||
styles: {
|
||||
|
|
@ -1189,4 +1189,85 @@ export const componentTypes = [
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Calendar',
|
||||
displayName: 'Calendar',
|
||||
description: 'Calendar',
|
||||
component: 'Calendar',
|
||||
defaultSize: {
|
||||
width: 700,
|
||||
height: 600,
|
||||
},
|
||||
others: {
|
||||
showOnDesktop: { type: 'toggle', displayName: 'Show on desktop' },
|
||||
showOnMobile: { type: 'toggle', displayName: 'Show on mobile' },
|
||||
},
|
||||
properties: {
|
||||
dateFormat: { type: 'code', displayName: 'Date format' },
|
||||
defaultDate: { type: 'code', displayName: 'Default date' },
|
||||
events: { type: 'code', displayName: 'Events' },
|
||||
resources: { type: 'code', displayName: 'Resources' },
|
||||
defaultView: { type: 'code', displayName: 'Default view' },
|
||||
displayToolbar: { type: 'toggle', displayName: 'Show toolbar' },
|
||||
displayViewSwitcher: { type: 'toggle', displayName: 'Show view switcher' },
|
||||
highlightToday: { type: 'toggle', displayName: 'Highlight today' },
|
||||
},
|
||||
events: {
|
||||
onCalendarEventSelect: { displayName: 'On Event Select' },
|
||||
onCalendarSlotSelect: { displayName: 'On Slot Select' },
|
||||
},
|
||||
styles: {
|
||||
visibility: { type: 'code', displayName: 'Visibility' },
|
||||
cellSizeInViewsClassifiedByResource: {
|
||||
type: 'select',
|
||||
displayName: 'Cell size in views classified by resource',
|
||||
options: [
|
||||
{ name: 'Compact', value: 'compact' },
|
||||
{ name: 'Spacious', value: 'spacious' },
|
||||
],
|
||||
},
|
||||
},
|
||||
exposedVariables: {
|
||||
selectedEvent: {},
|
||||
selectedSlots: {},
|
||||
},
|
||||
definition: {
|
||||
others: {
|
||||
showOnDesktop: { value: true },
|
||||
showOnMobile: { value: false },
|
||||
},
|
||||
properties: {
|
||||
dateFormat: {
|
||||
value: 'MM-DD-YYYY HH:mm:ss A Z',
|
||||
},
|
||||
defaultDate: {
|
||||
value: '{{moment().format("MM-DD-YYYY HH:mm:ss A Z")}}',
|
||||
},
|
||||
events: {
|
||||
value:
|
||||
"{{[\n\t\t{\n\t\t\t title: 'Sample event',\n\t\t\t start: `${moment().startOf('day').format('MM-DD-YYYY HH:mm:ss A Z')}`,\n\t\t\t end: `${moment().endOf('day').format('MM-DD-YYYY HH:mm:ss A Z')}`,\n\t\t\t allDay: false,\n\t\t\t color: '#4D72DA'\n\t\t}\n]}}",
|
||||
},
|
||||
resources: {
|
||||
value: '{{[]}}',
|
||||
},
|
||||
defaultView: {
|
||||
value: "{{'month'}}",
|
||||
},
|
||||
displayToolbar: {
|
||||
value: true,
|
||||
},
|
||||
displayViewSwitcher: {
|
||||
value: true,
|
||||
},
|
||||
highlightToday: {
|
||||
value: true,
|
||||
},
|
||||
},
|
||||
events: [],
|
||||
styles: {
|
||||
visibility: { value: '{{true}}' },
|
||||
cellSizeInViewsClassifiedByResource: { value: 'spacious' },
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -224,6 +224,48 @@ export async function onEvent(_ref, eventName, options, mode = 'edit') {
|
|||
);
|
||||
}
|
||||
|
||||
if (eventName === 'onCalendarEventSelect') {
|
||||
const { component, calendarEvent } = options;
|
||||
_self.setState(
|
||||
{
|
||||
currentState: {
|
||||
..._self.state.currentState,
|
||||
components: {
|
||||
..._self.state.currentState.components,
|
||||
[component.name]: {
|
||||
..._self.state.currentState.components[component.name],
|
||||
selectedEvent: { ...calendarEvent },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
() => {
|
||||
executeActionsForEventId(_ref, 'onCalendarEventSelect', component, mode);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (eventName === 'onCalendarSlotSelect') {
|
||||
const { component, selectedSlots } = options;
|
||||
_self.setState(
|
||||
{
|
||||
currentState: {
|
||||
..._self.state.currentState,
|
||||
components: {
|
||||
..._self.state.currentState.components,
|
||||
[component.name]: {
|
||||
..._self.state.currentState.components[component.name],
|
||||
selectedSlots,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
() => {
|
||||
executeActionsForEventId(_ref, 'onCalendarSlotSelect', component, mode);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (eventName === 'onTableActionButtonClicked') {
|
||||
const { component, data, action, rowId } = options;
|
||||
_self.setState(
|
||||
|
|
|
|||
|
|
@ -2391,6 +2391,104 @@ input[type='text'] {
|
|||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.calendar-widget.compact {
|
||||
.rbc-time-view-resources .rbc-time-header-content {
|
||||
min-width: auto;
|
||||
}
|
||||
|
||||
.rbc-time-view-resources .rbc-day-slot {
|
||||
min-width: 50px;
|
||||
}
|
||||
|
||||
.rbc-time-view-resources .rbc-header,
|
||||
.rbc-time-view-resources .rbc-day-bg {
|
||||
width: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-widget.dont-highlight-today {
|
||||
.rbc-today {
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
.rbc-current-time-indicator {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-widget {
|
||||
padding: 10px;
|
||||
background-color: white;
|
||||
|
||||
.rbc-day-slot .rbc-event, .rbc-day-slot .rbc-background-event {
|
||||
border-left: 3px solid #26598533;
|
||||
}
|
||||
|
||||
.rbc-toolbar {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.rbc-event {
|
||||
.rbc-event-label {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.rbc-off-range-bg {
|
||||
background-color: #f4f6fa;
|
||||
}
|
||||
|
||||
.rbc-toolbar {
|
||||
.rbc-btn-group {
|
||||
button {
|
||||
box-shadow: none;
|
||||
border-radius: 0;
|
||||
border-width: 1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-widget.hide-view-switcher {
|
||||
.rbc-toolbar {
|
||||
.rbc-btn-group:nth-of-type(3) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-widget.dark-mode {
|
||||
background-color: #1d2a39;
|
||||
|
||||
.rbc-toolbar {
|
||||
button {
|
||||
color: white;
|
||||
}
|
||||
|
||||
button:hover, button.rbc-active {
|
||||
color: black;
|
||||
}
|
||||
}
|
||||
|
||||
.rbc-off-range-bg {
|
||||
background-color: #2b394b;
|
||||
}
|
||||
|
||||
.rbc-selected-cell {
|
||||
background-color: #22242d;
|
||||
}
|
||||
|
||||
.rbc-today {
|
||||
background-color: #5a7ca8;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-widget.dark-mode.dont-highlight-today {
|
||||
.rbc-today {
|
||||
background-color: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar .navbar-nav {
|
||||
min-height: 2rem;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue