@axis-backstage/plugin-vacation-calendar 0.10.1 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # @axis-backstage/plugin-vacation-calendar
2
2
 
3
+ ## 0.11.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 85be688: Fix broken timeline layout in consuming apps. The `react-calendar-timeline`
8
+ package declares `sideEffects: false` with no exception for CSS, so its base
9
+ stylesheet was tree-shaken out of the bundle when this plugin was consumed by
10
+ a host app (it only appeared to work in this plugin's own dev server, which
11
+ does not tree-shake). The base timeline styles are now inlined into this
12
+ plugin's own CSS file, and the `sideEffects` field is updated to also cover
13
+ the compiled `*.css.esm.js` output so it survives bundling.
14
+
15
+ ## 0.11.0
16
+
17
+ ### Minor Changes
18
+
19
+ - 78d19b9: Migrate the vacation calendar to Backstage UI, TanStack Query v5, Day.js, and
20
+ react-calendar-timeline v0.30. The calendar now uses a Backstage UI date picker.
21
+
22
+ The migration removes a number of legacy Material UI, date-picker, and timeline
23
+ dependencies.
24
+
25
+ **Breaking:** Consumers must install and configure `@backstage/ui`.
26
+
27
+ ### Patch Changes
28
+
29
+ - 2569fb1: Updated to Backstage 1.52.1
30
+
3
31
  ## 0.10.1
4
32
 
5
33
  ### Patch Changes
@@ -0,0 +1,5 @@
1
+ import styleInject from '../../node_modules_dist/style-inject/dist/style-inject.es.esm.js';
2
+
3
+ var css_248z = "/*\n * Base react-calendar-timeline styles, inlined here instead of imported from\n * 'react-calendar-timeline/style.css'. That package declares \"sideEffects\": false\n * with no exception for CSS files, so bundlers can tree-shake the import away\n * entirely once this plugin is built and consumed by a host app.\n */\n.react-calendar-timeline * {\n box-sizing: border-box;\n}\n\n.react-calendar-timeline .rct-outer {\n display: block;\n overflow: hidden;\n white-space: nowrap;\n}\n\n.react-calendar-timeline .rct-scroll {\n display: inline-block;\n white-space: normal;\n vertical-align: top;\n overflow: hidden;\n touch-action: none;\n}\n\n.react-calendar-timeline .rct-item:hover {\n z-index: 88;\n}\n\n.react-calendar-timeline .rct-item .rct-item-content {\n position: sticky;\n left: 0;\n overflow: hidden;\n display: inline-block;\n border-radius: 2px;\n padding: 0 6px;\n height: 100%;\n}\n\n.react-calendar-timeline .rct-sidebar {\n overflow: hidden;\n white-space: normal;\n display: inline-block;\n vertical-align: top;\n position: relative;\n box-sizing: border-box;\n}\n\n.react-calendar-timeline .rct-sidebar.rct-sidebar-right {\n border-right: 0;\n border-left: 1px solid var(--bui-border-1, #bbb);\n}\n\n.react-calendar-timeline .rct-sidebar .rct-sidebar-row {\n padding: 0 4px;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n box-sizing: border-box;\n margin: 0;\n}\n\n.react-calendar-timeline .rct-sidebar .rct-sidebar-row.rct-sidebar-row-even {\n background: transparent;\n}\n\n.react-calendar-timeline .rct-vertical-lines .rct-vl {\n position: absolute;\n z-index: 30;\n}\n\n.react-calendar-timeline .rct-vertical-lines .rct-vl.rct-vl-first {\n border-left-width: 2px;\n}\n\n.react-calendar-timeline .rct-vertical-lines .rct-vl.rct-day-6,\n.react-calendar-timeline .rct-vertical-lines .rct-vl.rct-day-0 {\n background: #faf6e180;\n}\n\n.react-calendar-timeline .rct-horizontal-lines {\n user-select: none;\n}\n\n.react-calendar-timeline .rct-horizontal-lines .rct-hl-even,\n.react-calendar-timeline .rct-horizontal-lines .rct-hl-odd {\n box-sizing: border-box;\n z-index: 40;\n}\n\n.react-calendar-timeline .rct-horizontal-lines .rct-hl-even {\n background: transparent;\n}\n\n.react-calendar-timeline .rct-cursor-line {\n position: absolute;\n width: 2px;\n background: #2196f3;\n z-index: 51;\n}\n\n.react-calendar-timeline .rct-dateHeader {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n cursor: pointer;\n font-size: 14px;\n}\n\n.react-calendar-timeline .rct-dateHeader-primary {\n background-color: initial;\n}\n\n.react-calendar-timeline .rct-header-root {\n background: var(--bui-bg-neutral-2, #f5f5f5);\n border-bottom: 1px solid var(--bui-border-1, #bbb);\n}\n\n.react-calendar-timeline .rct-calendar-header {\n border: 1px solid var(--bui-border-1, #bbb);\n border-bottom: 0;\n}\n\n.react-calendar-timeline .rct-dateHeader {\n background-color: var(--bui-bg-neutral-1, #fafafa);\n border-left: 1px solid var(--bui-border-1, #bbb);\n border-bottom: 1px solid var(--bui-border-1, #bbb);\n color: var(--bui-fg-primary, #333);\n}\n\n.react-calendar-timeline .rct-dateHeader-primary {\n background-color: var(--bui-bg-neutral-2, #e0e0e0);\n color: var(--bui-fg-primary, #333);\n}\n\n.react-calendar-timeline .rct-sidebar {\n border-right: 1px solid var(--bui-border-1, #bbb);\n}\n\n.react-calendar-timeline .timeline-sidebar-header {\n border-bottom: 1px solid var(--bui-border-1, #bbb);\n}\n\n.react-calendar-timeline .rct-sidebar .rct-sidebar-row {\n border-bottom: 1px solid var(--bui-border-1, #bbb);\n}\n\n.react-calendar-timeline .rct-sidebar .rct-sidebar-row.rct-sidebar-row-odd {\n background: var(--bui-bg-neutral-1, rgba(0, 0, 0, 0.05));\n}\n\n.react-calendar-timeline .rct-horizontal-lines .rct-hl-odd {\n background: var(--bui-bg-neutral-1, rgba(0, 0, 0, 0.05));\n}\n\n.react-calendar-timeline .rct-horizontal-lines .rct-hl-even,\n.react-calendar-timeline .rct-horizontal-lines .rct-hl-odd {\n border-bottom: 1px solid var(--bui-border-1, #bbb);\n}\n\n.react-calendar-timeline .rct-vertical-lines .rct-vl {\n border-left: 1px solid var(--bui-border-1, #bbb);\n}\n\n.custom-group {\n display: flex;\n align-items: center;\n gap: 5px;\n white-space: nowrap;\n}\n";
4
+ styleInject(css_248z);
5
+ //# sourceMappingURL=CalendarCard.css.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CalendarCard.css.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;"}
@@ -1,55 +1,32 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
- import 'react-calendar-timeline/lib/Timeline.css';
2
+ import './CalendarCard.css.esm.js';
3
3
  import { useState } from 'react';
4
4
  import useAsync from 'react-use/lib/useAsync';
5
5
  import Timeline, { TimelineHeaders, SidebarHeader, DateHeader } from 'react-calendar-timeline';
6
- import { DateTime } from 'luxon';
6
+ import dayjs from 'dayjs';
7
7
  import { useApi } from '@backstage/core-plugin-api';
8
8
  import { useEntity, catalogApiRef } from '@backstage/plugin-catalog-react';
9
9
  import { ErrorPanel, Content, ContentHeader, SupportButton, Progress, Link, Avatar } from '@backstage/core-components';
10
+ import { Box, Flex, Button } from '@backstage/ui';
10
11
  import { DateSelector } from '../DateSelector/DateSelector.esm.js';
11
12
  import { getGroups, getScheduleItems } from './lib.esm.js';
12
13
  import { fetchUserEntities, fetchGroupEntities } from './fetch.esm.js';
13
14
  import { useAvailability } from '../../hooks/useAvailibility.esm.js';
14
15
  import { useSignIn } from '../../hooks/useSignIn.esm.js';
15
16
  import { SignInContent } from '../SignInContent/SignInContent.esm.js';
16
- import MuiLink from '@mui/material/Link';
17
- import Button from '@mui/material/Button';
18
- import Box from '@mui/material/Box';
19
17
  import Typography from '@mui/material/Typography';
20
- import Stack from '@mui/material/Stack';
21
18
 
22
19
  const DEFAULT_NUM_DAYS = 60;
23
- const IntervalDateHeader = (props) => {
24
- return /* @__PURE__ */ jsx(
25
- MuiLink,
26
- {
27
- sx: {
28
- display: "flex",
29
- alignItems: "center",
30
- justifyContent: "center",
31
- height: "100%",
32
- borderBottom: "1px solid #bbb",
33
- cursor: "pointer",
34
- fontSize: "14px",
35
- borderLeft: "2px solid #bbb",
36
- color: (theme) => theme.palette.text.primary,
37
- position: "absolute",
38
- width: props?.intervalContext.interval.labelWidth,
39
- left: props?.intervalContext.interval.left
40
- },
41
- onClick: props?.getIntervalProps().onClick,
42
- children: props?.intervalContext.intervalText
43
- }
44
- );
45
- };
20
+ const DAY_IN_MILLISECONDS = 24 * 60 * 60 * 1e3;
21
+ const DAY_HEADER_MAX_ZOOM = DEFAULT_NUM_DAYS * DAY_IN_MILLISECONDS;
46
22
  const CalendarCard = () => {
47
23
  const { entity } = useEntity();
48
24
  const catalogApi = useApi(catalogApiRef);
49
- const [startDate, setStartDate] = useState(DateTime.now());
25
+ const [startDate, setStartDate] = useState(dayjs());
50
26
  const [endDate, setEndDate] = useState(
51
- DateTime.now().endOf("day").plus({ days: DEFAULT_NUM_DAYS })
27
+ dayjs().endOf("day").add(DEFAULT_NUM_DAYS, "day")
52
28
  );
29
+ const [headerUnit, setHeaderUnit] = useState("day");
53
30
  const { isSignedIn, isInitialized, signIn } = useSignIn();
54
31
  useAsync(async () => signIn(true), [signIn]);
55
32
  const isUserEntity = entity.kind.toLowerCase() === "user" && entity.metadata.name;
@@ -57,7 +34,7 @@ const CalendarCard = () => {
57
34
  return isUserEntity ? fetchUserEntities(catalogApi, entity) : fetchGroupEntities(catalogApi, entity);
58
35
  }, [catalogApi, entity]);
59
36
  const {
60
- availablity,
37
+ availability,
61
38
  error,
62
39
  isLoading: isAvailabilityLoading,
63
40
  isFetching: isAvailabilityFetching,
@@ -65,8 +42,8 @@ const CalendarCard = () => {
65
42
  fetchNextPage
66
43
  } = useAvailability(users, startDate, endDate, isSignedIn);
67
44
  const showLoader = isAvailabilityLoading || isAvailabilityFetching || !isInitialized;
68
- const [groups, groupIndexMap] = getGroups(availablity, isUserEntity, users);
69
- const scheduleItems = getScheduleItems(availablity, groupIndexMap);
45
+ const [groups, groupIndexMap] = getGroups(availability, isUserEntity, users);
46
+ const scheduleItems = getScheduleItems(availability, groupIndexMap);
70
47
  if (users?.length === 0) {
71
48
  return /* @__PURE__ */ jsx(
72
49
  ErrorPanel,
@@ -99,20 +76,21 @@ const CalendarCard = () => {
99
76
  ] })
100
77
  ] }) }) }),
101
78
  /* @__PURE__ */ jsxs(Box, { children: [
102
- /* @__PURE__ */ jsxs(Stack, { direction: "row", gap: 3, alignItems: "center", children: [
79
+ /* @__PURE__ */ jsxs(Flex, { direction: "row", gap: "3", align: "end", children: [
103
80
  /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(
104
81
  DateSelector,
105
82
  {
106
83
  onDateChange: (d) => {
107
- if (d instanceof DateTime) {
108
- const { days } = endDate.diff(d, "days").toObject();
84
+ if (d) {
85
+ const days = endDate.diff(d, "day");
109
86
  if (days && Math.abs(days) > DEFAULT_NUM_DAYS) {
110
- setEndDate(d.endOf("day").plus({ days: DEFAULT_NUM_DAYS }));
87
+ setEndDate(d.endOf("day").add(DEFAULT_NUM_DAYS, "day"));
111
88
  }
89
+ setHeaderUnit("day");
112
90
  setStartDate(d);
113
91
  }
114
92
  },
115
- initalDate: startDate,
93
+ initialDate: startDate,
116
94
  label: "Start Date"
117
95
  }
118
96
  ) }),
@@ -120,61 +98,65 @@ const CalendarCard = () => {
120
98
  DateSelector,
121
99
  {
122
100
  onDateChange: (d) => {
123
- if (d instanceof DateTime) {
124
- const { days } = startDate.diff(d, "days").toObject();
101
+ if (d) {
102
+ const days = startDate.diff(d, "day");
125
103
  if (days && Math.abs(days) > DEFAULT_NUM_DAYS) {
126
104
  setStartDate(
127
- d.endOf("day").minus({ days: DEFAULT_NUM_DAYS })
105
+ d.endOf("day").subtract(DEFAULT_NUM_DAYS, "day")
128
106
  );
129
107
  }
108
+ setHeaderUnit("day");
130
109
  setEndDate(d);
131
110
  }
132
111
  },
133
- initalDate: endDate,
112
+ initialDate: endDate,
134
113
  label: "End Date"
135
114
  }
136
115
  ) }),
137
- /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(
116
+ /* @__PURE__ */ jsx(
138
117
  Button,
139
118
  {
140
119
  onClick: () => {
141
120
  fetchNextPage();
142
121
  },
143
- disabled: showLoader || !hasNextPage,
144
- variant: "contained",
145
- color: "primary",
122
+ isDisabled: showLoader || !hasNextPage,
123
+ variant: "secondary",
146
124
  children: "Show more Users"
147
125
  }
148
- ) })
126
+ )
149
127
  ] }),
150
- showLoader && /* @__PURE__ */ jsx(Box, { py: 2, children: /* @__PURE__ */ jsx(Progress, { variant: "query" }) }),
151
- !isSignedIn && isInitialized && /* @__PURE__ */ jsx(Box, { p: 1, pb: 0, minHeight: 200, maxHeight: 602, overflow: "auto", children: /* @__PURE__ */ jsx(SignInContent, { handleAuthClick: () => signIn(false) }) }),
152
- !isAvailabilityLoading && isSignedIn && /* @__PURE__ */ jsx(Box, { mt: 3, pb: 0, minHeight: 200, overflow: "auto", children: /* @__PURE__ */ jsx(
153
- Timeline,
128
+ showLoader && /* @__PURE__ */ jsx(Box, { py: "2", children: /* @__PURE__ */ jsx(Progress, { variant: "query" }) }),
129
+ !isSignedIn && isInitialized && /* @__PURE__ */ jsx(
130
+ Box,
131
+ {
132
+ p: "1",
133
+ pb: "0",
134
+ minHeight: "200px",
135
+ maxHeight: "602px",
136
+ style: { overflow: "auto" },
137
+ children: /* @__PURE__ */ jsx(SignInContent, { handleAuthClick: () => signIn(false) })
138
+ }
139
+ ),
140
+ !isAvailabilityLoading && isSignedIn && /* @__PURE__ */ jsx(
141
+ "div",
154
142
  {
155
- groups,
156
- sidebarWidth: 250,
157
- groupRenderer: ({ group }) => {
158
- return /* @__PURE__ */ jsx(
159
- Link,
160
- {
161
- to: `/catalog/default/user/${group.entity?.metadata.name}`,
162
- children: /* @__PURE__ */ jsxs(
163
- "div",
143
+ style: {
144
+ marginTop: "var(--bui-space-3)",
145
+ minHeight: "200px",
146
+ overflow: "auto"
147
+ },
148
+ children: /* @__PURE__ */ jsx(
149
+ Timeline,
150
+ {
151
+ groups,
152
+ sidebarWidth: 250,
153
+ groupRenderer: ({ group }) => {
154
+ return /* @__PURE__ */ jsx(
155
+ Link,
164
156
  {
165
- className: "custom-group",
166
- style: {
167
- background: group.highlight ? "linear-gradient(90deg, #FFCC33A0, transparent 100%)" : "",
168
- marginLeft: "-4px",
169
- paddingLeft: "4px",
170
- display: "flex",
171
- whiteSpace: "nowrap",
172
- flexWrap: "nowrap",
173
- flexDirection: "row",
174
- gap: "5px"
175
- },
176
- children: [
177
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
157
+ to: `/catalog/default/user/${group.entity?.metadata.name}`,
158
+ children: /* @__PURE__ */ jsxs("div", { className: "custom-group", children: [
159
+ /* @__PURE__ */ jsx(
178
160
  Avatar,
179
161
  {
180
162
  displayName: group.entity?.metadata.displayName,
@@ -184,44 +166,39 @@ const CalendarCard = () => {
184
166
  height: 30
185
167
  }
186
168
  }
187
- ) }),
188
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx("span", { className: "title", children: group.title }) })
189
- ]
169
+ ),
170
+ /* @__PURE__ */ jsx("span", { className: "title", children: group.title })
171
+ ] })
190
172
  }
191
- )
192
- }
193
- );
194
- },
195
- items: scheduleItems,
196
- itemTouchSendsClick: false,
197
- defaultTimeStart: startDate.toJSDate(),
198
- defaultTimeEnd: endDate.toJSDate(),
199
- children: /* @__PURE__ */ jsxs(
200
- TimelineHeaders,
201
- {
202
- style: {
203
- backgroundColor: "transparent",
204
- color: "black",
205
- position: "sticky",
206
- top: "-6px"
173
+ );
207
174
  },
208
- children: [
175
+ items: scheduleItems,
176
+ itemTouchSendsClick: false,
177
+ defaultTimeStart: startDate.valueOf(),
178
+ defaultTimeEnd: endDate.valueOf(),
179
+ onZoom: ({ visibleTimeStart, visibleTimeEnd }) => {
180
+ setHeaderUnit(
181
+ visibleTimeEnd - visibleTimeStart <= DAY_HEADER_MAX_ZOOM ? "day" : "month"
182
+ );
183
+ },
184
+ children: /* @__PURE__ */ jsxs(TimelineHeaders, { children: [
209
185
  /* @__PURE__ */ jsx(SidebarHeader, { children: ({ getRootProps }) => {
210
- return /* @__PURE__ */ jsx("div", { ...getRootProps() });
186
+ return /* @__PURE__ */ jsx(
187
+ "div",
188
+ {
189
+ ...getRootProps(),
190
+ className: "timeline-sidebar-header"
191
+ }
192
+ );
211
193
  } }),
212
- /* @__PURE__ */ jsx(
213
- DateHeader,
214
- {
215
- unit: "primaryHeader",
216
- intervalRenderer: IntervalDateHeader
217
- }
218
- ),
219
- /* @__PURE__ */ jsx(DateHeader, { intervalRenderer: IntervalDateHeader })
220
- ]
221
- }
194
+ /* @__PURE__ */ jsx(DateHeader, { unit: headerUnit === "day" ? "month" : "year" }),
195
+ /* @__PURE__ */ jsx(DateHeader, { unit: headerUnit })
196
+ ] })
197
+ },
198
+ `${startDate.valueOf()}-${endDate.valueOf()}`
222
199
  )
223
200
  }
224
- ) })
201
+ )
225
202
  ] })
226
203
  ] });
227
204
  };
@@ -1 +1 @@
1
- {"version":3,"file":"CalendarCard.esm.js","sources":["../../../src/components/CalendarCard/CalendarCard.tsx"],"sourcesContent":["import 'react-calendar-timeline/lib/Timeline.css';\nimport { ReactNode, useState } from 'react';\nimport useAsync from 'react-use/lib/useAsync';\nimport Timeline, {\n TimelineHeaders,\n SidebarHeader,\n DateHeader,\n IntervalRenderer,\n} from 'react-calendar-timeline';\nimport { DateTime } from 'luxon';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { useEntity, catalogApiRef } from '@backstage/plugin-catalog-react';\nimport {\n Content,\n ContentHeader,\n SupportButton,\n Link,\n ErrorPanel,\n Progress,\n Avatar,\n} from '@backstage/core-components';\nimport { DateSelector } from '../DateSelector';\nimport { getGroups, getScheduleItems } from './lib';\nimport { fetchGroupEntities, fetchUserEntities } from './fetch';\nimport { useAvailability } from '../../hooks/useAvailibility';\nimport { useSignIn } from '../../hooks';\nimport { SignInContent } from '../SignInContent';\nimport MuiLink from '@mui/material/Link';\nimport Button from '@mui/material/Button';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport Stack from '@mui/material/Stack';\n\nimport { Theme } from '@mui/material/styles';\n\nconst DEFAULT_NUM_DAYS = 60;\n\nconst IntervalDateHeader = (props?: IntervalRenderer<object>): ReactNode => {\n return (\n <MuiLink\n sx={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n height: '100%',\n borderBottom: '1px solid #bbb',\n cursor: 'pointer',\n fontSize: '14px',\n borderLeft: '2px solid #bbb',\n color: (theme: Theme) => theme.palette.text.primary,\n position: 'absolute',\n width: props?.intervalContext.interval.labelWidth,\n left: props?.intervalContext.interval.left,\n }}\n onClick={props?.getIntervalProps().onClick}\n >\n {props?.intervalContext.intervalText}\n </MuiLink>\n );\n};\n\nexport const CalendarCard = () => {\n const { entity } = useEntity();\n const catalogApi = useApi(catalogApiRef);\n\n const [startDate, setStartDate] = useState(DateTime.now());\n const [endDate, setEndDate] = useState(\n DateTime.now().endOf('day').plus({ days: DEFAULT_NUM_DAYS }),\n );\n\n const { isSignedIn, isInitialized, signIn } = useSignIn();\n\n useAsync(async () => signIn(true), [signIn]);\n\n const isUserEntity =\n entity.kind.toLowerCase() === 'user' && entity.metadata.name;\n\n const { value: users } = useAsync(async () => {\n return isUserEntity\n ? fetchUserEntities(catalogApi, entity)\n : fetchGroupEntities(catalogApi, entity);\n }, [catalogApi, entity]);\n\n const {\n availablity,\n error,\n isLoading: isAvailabilityLoading,\n isFetching: isAvailabilityFetching,\n hasNextPage,\n fetchNextPage,\n } = useAvailability(users, startDate, endDate, isSignedIn);\n\n const showLoader =\n isAvailabilityLoading || isAvailabilityFetching || !isInitialized;\n\n const [groups, groupIndexMap] = getGroups(availablity, isUserEntity, users);\n const scheduleItems = getScheduleItems(availablity, groupIndexMap);\n\n if (users?.length === 0) {\n return (\n <ErrorPanel\n title=\"No users found.\"\n defaultExpanded\n error={Error('No users found for current entity.')}\n />\n );\n }\n if (error instanceof Error) {\n return (\n <ErrorPanel\n title=\"Microsoft Graph Error.\"\n defaultExpanded\n error={error as any}\n />\n );\n }\n\n return (\n <Content>\n <ContentHeader title=\"Out of Office Calendar\">\n <SupportButton title=\"Backstage Out Of Office Calendar\">\n <Box>\n <Typography variant=\"h6\">How it works</Typography>\n <Typography>\n The \"Out of Office\"-calendar shows Away events. If you want your\n calendar events to be seen in the \"Out of Office\"-calendar, be\n sure to mark your presence as \"Away\" in outlook.\n </Typography>\n <Typography variant=\"h6\">Limitations</Typography>\n <Typography>\n Due to limitations in the Microsoft Graph API the maximum range of\n the dates is {DEFAULT_NUM_DAYS} days.\n </Typography>\n </Box>\n </SupportButton>\n </ContentHeader>\n\n <Box>\n <Stack direction=\"row\" gap={3} alignItems=\"center\">\n <Box>\n <DateSelector\n onDateChange={d => {\n if (d instanceof DateTime) {\n const { days } = endDate.diff(d, 'days').toObject();\n if (days && Math.abs(days) > DEFAULT_NUM_DAYS) {\n setEndDate(d.endOf('day').plus({ days: DEFAULT_NUM_DAYS }));\n }\n setStartDate(d);\n }\n }}\n initalDate={startDate}\n label=\"Start Date\"\n />\n </Box>\n <Box>\n <DateSelector\n onDateChange={d => {\n if (d instanceof DateTime) {\n const { days } = startDate.diff(d, 'days').toObject();\n if (days && Math.abs(days) > DEFAULT_NUM_DAYS) {\n setStartDate(\n d.endOf('day').minus({ days: DEFAULT_NUM_DAYS }),\n );\n }\n setEndDate(d as DateTime);\n }\n }}\n initalDate={endDate}\n label=\"End Date\"\n />\n </Box>\n <Box>\n <Button\n onClick={() => {\n fetchNextPage();\n }}\n disabled={showLoader || !hasNextPage}\n variant=\"contained\"\n color=\"primary\"\n >\n Show more Users\n </Button>\n </Box>\n </Stack>\n\n {showLoader && (\n <Box py={2}>\n <Progress variant=\"query\" />\n </Box>\n )}\n {!isSignedIn && isInitialized && (\n <Box p={1} pb={0} minHeight={200} maxHeight={602} overflow=\"auto\">\n <SignInContent handleAuthClick={() => signIn(false)} />\n </Box>\n )}\n {!isAvailabilityLoading && isSignedIn && (\n <Box mt={3} pb={0} minHeight={200} overflow=\"auto\">\n <Timeline\n groups={groups}\n sidebarWidth={250}\n groupRenderer={({ group }) => {\n return (\n <Link\n to={`/catalog/default/user/${group.entity?.metadata.name}`}\n >\n <div\n className=\"custom-group\"\n style={{\n background: group.highlight\n ? 'linear-gradient(90deg, #FFCC33A0, transparent 100%)'\n : '',\n marginLeft: '-4px',\n paddingLeft: '4px',\n display: 'flex',\n whiteSpace: 'nowrap',\n flexWrap: 'nowrap',\n flexDirection: 'row',\n gap: '5px',\n }}\n >\n <div>\n <Avatar\n displayName={\n group.entity?.metadata.displayName as string\n }\n picture={group.entity?.spec.profile?.picture}\n customStyles={{\n width: 30,\n height: 30,\n }}\n />\n </div>\n <div>\n <span className=\"title\">{group.title}</span>\n </div>\n </div>\n </Link>\n );\n }}\n items={scheduleItems as any}\n itemTouchSendsClick={false}\n defaultTimeStart={startDate.toJSDate()}\n defaultTimeEnd={endDate.toJSDate()}\n >\n <TimelineHeaders\n style={{\n backgroundColor: 'transparent',\n color: 'black',\n position: 'sticky',\n top: '-6px',\n }}\n >\n <SidebarHeader>\n {({ getRootProps }) => {\n return <div {...getRootProps()} />;\n }}\n </SidebarHeader>\n <DateHeader\n unit=\"primaryHeader\"\n intervalRenderer={IntervalDateHeader}\n />\n <DateHeader intervalRenderer={IntervalDateHeader} />\n </TimelineHeaders>\n </Timeline>\n </Box>\n )}\n </Box>\n </Content>\n );\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"CalendarCard.esm.js","sources":["../../../src/components/CalendarCard/CalendarCard.tsx"],"sourcesContent":["import './CalendarCard.css';\nimport { useState } from 'react';\nimport useAsync from 'react-use/lib/useAsync';\nimport Timeline, {\n TimelineHeaders,\n SidebarHeader,\n DateHeader,\n} from 'react-calendar-timeline';\nimport dayjs from 'dayjs';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { useEntity, catalogApiRef } from '@backstage/plugin-catalog-react';\nimport {\n Content,\n ContentHeader,\n SupportButton,\n Link,\n ErrorPanel,\n Progress,\n Avatar,\n} from '@backstage/core-components';\nimport { Box, Button, Flex } from '@backstage/ui';\nimport { DateSelector } from '../DateSelector';\nimport { getGroups, getScheduleItems } from './lib';\nimport { fetchGroupEntities, fetchUserEntities } from './fetch';\nimport { useAvailability } from '../../hooks/useAvailibility';\nimport { useSignIn } from '../../hooks';\nimport { SignInContent } from '../SignInContent';\nimport Typography from '@mui/material/Typography';\n\nconst DEFAULT_NUM_DAYS = 60;\nconst DAY_IN_MILLISECONDS = 24 * 60 * 60 * 1000;\nconst DAY_HEADER_MAX_ZOOM = DEFAULT_NUM_DAYS * DAY_IN_MILLISECONDS;\n\nexport const CalendarCard = () => {\n const { entity } = useEntity();\n const catalogApi = useApi(catalogApiRef);\n\n const [startDate, setStartDate] = useState(dayjs());\n const [endDate, setEndDate] = useState(\n dayjs().endOf('day').add(DEFAULT_NUM_DAYS, 'day'),\n );\n const [headerUnit, setHeaderUnit] = useState<'day' | 'month'>('day');\n\n const { isSignedIn, isInitialized, signIn } = useSignIn();\n\n useAsync(async () => signIn(true), [signIn]);\n\n const isUserEntity =\n entity.kind.toLowerCase() === 'user' && entity.metadata.name;\n\n const { value: users } = useAsync(async () => {\n return isUserEntity\n ? fetchUserEntities(catalogApi, entity)\n : fetchGroupEntities(catalogApi, entity);\n }, [catalogApi, entity]);\n\n const {\n availability,\n error,\n isLoading: isAvailabilityLoading,\n isFetching: isAvailabilityFetching,\n hasNextPage,\n fetchNextPage,\n } = useAvailability(users, startDate, endDate, isSignedIn);\n\n const showLoader =\n isAvailabilityLoading || isAvailabilityFetching || !isInitialized;\n\n const [groups, groupIndexMap] = getGroups(availability, isUserEntity, users);\n const scheduleItems = getScheduleItems(availability, groupIndexMap);\n\n if (users?.length === 0) {\n return (\n <ErrorPanel\n title=\"No users found.\"\n defaultExpanded\n error={Error('No users found for current entity.')}\n />\n );\n }\n if (error instanceof Error) {\n return (\n <ErrorPanel\n title=\"Microsoft Graph Error.\"\n defaultExpanded\n error={error as any}\n />\n );\n }\n\n return (\n <Content>\n <ContentHeader title=\"Out of Office Calendar\">\n <SupportButton title=\"Backstage Out Of Office Calendar\">\n <Box>\n <Typography variant=\"h6\">How it works</Typography>\n <Typography>\n The \"Out of Office\"-calendar shows Away events. If you want your\n calendar events to be seen in the \"Out of Office\"-calendar, be\n sure to mark your presence as \"Away\" in outlook.\n </Typography>\n <Typography variant=\"h6\">Limitations</Typography>\n <Typography>\n Due to limitations in the Microsoft Graph API the maximum range of\n the dates is {DEFAULT_NUM_DAYS} days.\n </Typography>\n </Box>\n </SupportButton>\n </ContentHeader>\n\n <Box>\n <Flex direction=\"row\" gap=\"3\" align=\"end\">\n <Box>\n <DateSelector\n onDateChange={d => {\n if (d) {\n const days = endDate.diff(d, 'day');\n if (days && Math.abs(days) > DEFAULT_NUM_DAYS) {\n setEndDate(d.endOf('day').add(DEFAULT_NUM_DAYS, 'day'));\n }\n setHeaderUnit('day');\n setStartDate(d);\n }\n }}\n initialDate={startDate}\n label=\"Start Date\"\n />\n </Box>\n <Box>\n <DateSelector\n onDateChange={d => {\n if (d) {\n const days = startDate.diff(d, 'day');\n if (days && Math.abs(days) > DEFAULT_NUM_DAYS) {\n setStartDate(\n d.endOf('day').subtract(DEFAULT_NUM_DAYS, 'day'),\n );\n }\n setHeaderUnit('day');\n setEndDate(d);\n }\n }}\n initialDate={endDate}\n label=\"End Date\"\n />\n </Box>\n <Button\n onClick={() => {\n fetchNextPage();\n }}\n isDisabled={showLoader || !hasNextPage}\n variant=\"secondary\"\n >\n Show more Users\n </Button>\n </Flex>\n {showLoader && (\n <Box py=\"2\">\n <Progress variant=\"query\" />\n </Box>\n )}\n {!isSignedIn && isInitialized && (\n <Box\n p=\"1\"\n pb=\"0\"\n minHeight=\"200px\"\n maxHeight=\"602px\"\n style={{ overflow: 'auto' }}\n >\n <SignInContent handleAuthClick={() => signIn(false)} />\n </Box>\n )}\n {!isAvailabilityLoading && isSignedIn && (\n <div\n style={{\n marginTop: 'var(--bui-space-3)',\n minHeight: '200px',\n overflow: 'auto',\n }}\n >\n <Timeline\n key={`${startDate.valueOf()}-${endDate.valueOf()}`}\n groups={groups}\n sidebarWidth={250}\n groupRenderer={({ group }) => {\n return (\n <Link\n to={`/catalog/default/user/${group.entity?.metadata.name}`}\n >\n <div className=\"custom-group\">\n <Avatar\n displayName={\n group.entity?.metadata.displayName as string\n }\n picture={group.entity?.spec.profile?.picture}\n customStyles={{\n width: 30,\n height: 30,\n }}\n />\n <span className=\"title\">{group.title}</span>\n </div>\n </Link>\n );\n }}\n items={scheduleItems as any}\n itemTouchSendsClick={false}\n defaultTimeStart={startDate.valueOf()}\n defaultTimeEnd={endDate.valueOf()}\n onZoom={({ visibleTimeStart, visibleTimeEnd }) => {\n setHeaderUnit(\n visibleTimeEnd - visibleTimeStart <= DAY_HEADER_MAX_ZOOM\n ? 'day'\n : 'month',\n );\n }}\n >\n <TimelineHeaders>\n <SidebarHeader>\n {({ getRootProps }) => {\n return (\n <div\n {...getRootProps()}\n className=\"timeline-sidebar-header\"\n />\n );\n }}\n </SidebarHeader>\n <DateHeader unit={headerUnit === 'day' ? 'month' : 'year'} />\n <DateHeader unit={headerUnit} />\n </TimelineHeaders>\n </Timeline>\n </div>\n )}\n </Box>\n </Content>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -1,40 +1,38 @@
1
- import { head } from 'lodash';
2
- import { DateTime } from 'luxon';
1
+ import dayjs from 'dayjs';
3
2
 
4
3
  const isTimeLineItem = (item) => {
5
4
  return item !== void 0;
6
5
  };
7
6
  const getFullName = (users, userId) => {
8
- const name = head(userId.split("@"));
7
+ const [name] = userId.split("@");
9
8
  const user = users.find((u) => u.metadata.name === name);
10
9
  if (user) return user.spec.profile?.displayName;
11
10
  return userId;
12
11
  };
13
12
  const getUser = (users, userId) => {
14
- const name = head(userId.split("@"));
15
- const user = users.find((u) => u.metadata.name === name);
16
- return user;
13
+ const [name] = userId.split("@");
14
+ return users.find((u) => u.metadata.name === name);
17
15
  };
18
- const getScheduleItems = (availablity, groupIndexMap) => {
19
- return availablity ? availablity?.pages.flatMap((p) => p).flatMap(
16
+ const getScheduleItems = (availability, groupIndexMap) => {
17
+ return availability ? availability.pages.flatMap((p) => p).flatMap(
20
18
  (a, i) => (
21
19
  // @ts-ignore
22
20
  a.scheduleItems?.filter((scheduleItem) => scheduleItem.status === "oof").map((s) => ({
23
21
  id: Date.now().toString(36) + Math.random().toString(36).slice(2),
24
22
  group: groupIndexMap?.get(i) ?? i,
25
- start_time: DateTime.fromISO(s.start?.dateTime),
26
- end_time: DateTime.fromISO(s.end?.dateTime),
23
+ start_time: dayjs(s.start?.dateTime),
24
+ end_time: dayjs(s.end?.dateTime),
27
25
  canMove: false,
28
26
  canResize: false
29
27
  }))
30
28
  )
31
29
  ).filter(isTimeLineItem) : [];
32
30
  };
33
- const getGroups = (availablity, isUserEntity, users) => {
34
- if (!availablity) {
31
+ const getGroups = (availability, isUserEntity, users) => {
32
+ if (!availability) {
35
33
  return [[], /* @__PURE__ */ new Map()];
36
34
  }
37
- const flattenedSchedules = availablity.pages.flatMap((p) => p).map((a, originalIndex) => ({
35
+ const flattenedSchedules = availability.pages.flatMap((p) => p).map((a, originalIndex) => ({
38
36
  originalIndex,
39
37
  schedule: a,
40
38
  title: getFullName(users || [], a.scheduleId || "")
@@ -48,7 +46,7 @@ const getGroups = (availablity, isUserEntity, users) => {
48
46
  sortedSchedules.map((item, newIndex) => [item.originalIndex, newIndex])
49
47
  );
50
48
  const groups = sortedSchedules.map((item, newIndex) => {
51
- const isHighlighted = isUserEntity && item.schedule.scheduleId && isUserEntity === head(item.schedule.scheduleId.split("@"));
49
+ const isHighlighted = isUserEntity && item.schedule.scheduleId && isUserEntity === item.schedule.scheduleId?.split("@")[0];
52
50
  return {
53
51
  id: newIndex,
54
52
  highlight: !!isHighlighted,
@@ -1 +1 @@
1
- {"version":3,"file":"lib.esm.js","sources":["../../../src/components/CalendarCard/lib.ts"],"sourcesContent":["import { TimelineItemBase } from 'react-calendar-timeline';\nimport { UserEntity, UserEntityV1alpha1 } from '@backstage/catalog-model';\nimport { ScheduleInformation } from '@microsoft/microsoft-graph-types';\nimport { InfiniteData } from '@tanstack/react-query';\nimport { head } from 'lodash';\nimport { DateTime } from 'luxon';\n\nconst isTimeLineItem = (\n item: TimelineItemBase<any> | undefined,\n): item is TimelineItemBase<any> => {\n return item !== undefined;\n};\n\nconst getFullName = (users: UserEntity[], userId: string) => {\n const name = head(userId.split('@'));\n const user = users.find(u => u.metadata.name === name);\n\n if (user) return user.spec.profile?.displayName;\n return userId;\n};\n\nconst getUser = (users: UserEntity[], userId: string) => {\n const name = head(userId.split('@'));\n const user = users.find(u => u.metadata.name === name);\n\n return user;\n};\n\nexport const getScheduleItems = (\n availablity: InfiniteData<ScheduleInformation[]> | undefined,\n groupIndexMap?: Map<number, number>,\n) => {\n return availablity\n ? availablity?.pages\n .flatMap(p => p)\n // @ts-ignore\n .flatMap((a, i) =>\n // @ts-ignore\n a.scheduleItems\n // @ts-ignore\n ?.filter(scheduleItem => scheduleItem.status === 'oof')\n // @ts-ignore\n .map(s => ({\n id: Date.now().toString(36) + Math.random().toString(36).slice(2),\n group: groupIndexMap?.get(i) ?? i,\n start_time: DateTime.fromISO(s.start?.dateTime!),\n end_time: DateTime.fromISO(s.end?.dateTime!),\n canMove: false,\n canResize: false,\n })),\n )\n .filter(isTimeLineItem)\n : [];\n};\n\nexport const getGroups = (\n availablity: InfiniteData<ScheduleInformation[]> | undefined,\n isUserEntity: string | false,\n users: UserEntityV1alpha1[] | undefined,\n): [\n groups: Array<{\n id: number;\n highlight: boolean;\n title: string;\n entity?: UserEntity;\n height: number;\n }>,\n groupIndexMap: Map<number, number>,\n] => {\n if (!availablity) {\n return [[], new Map()];\n }\n\n const flattenedSchedules = availablity.pages\n .flatMap(p => p)\n .map((a, originalIndex) => ({\n originalIndex,\n schedule: a,\n title: getFullName(users || [], a.scheduleId || ''),\n }));\n\n // Sort by title (display name) alphabetically\n const sortedSchedules = [...flattenedSchedules].sort((a, b) => {\n const titleA = a.title || '';\n const titleB = b.title || '';\n return titleA.localeCompare(titleB);\n });\n\n // Create mapping from original index to new sorted index\n const groupIndexMap = new Map(\n sortedSchedules.map((item, newIndex) => [item.originalIndex, newIndex]),\n );\n\n const groups = sortedSchedules.map((item, newIndex) => {\n const isHighlighted =\n isUserEntity &&\n item.schedule.scheduleId &&\n isUserEntity === head(item.schedule.scheduleId.split('@'));\n\n return {\n id: newIndex,\n highlight: !!isHighlighted,\n title: item.title || '',\n entity: getUser(users || [], item.schedule.scheduleId || ''),\n height: 30,\n };\n });\n\n return [groups, groupIndexMap];\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"lib.esm.js","sources":["../../../src/components/CalendarCard/lib.ts"],"sourcesContent":["import { TimelineItemBase } from 'react-calendar-timeline';\nimport { UserEntity, UserEntityV1alpha1 } from '@backstage/catalog-model';\nimport { ScheduleInformation } from '@microsoft/microsoft-graph-types';\nimport { InfiniteData } from '@tanstack/react-query';\nimport dayjs from 'dayjs';\n\nconst isTimeLineItem = (\n item: TimelineItemBase<any> | undefined,\n): item is TimelineItemBase<any> => {\n return item !== undefined;\n};\n\nconst getFullName = (users: UserEntity[], userId: string) => {\n const [name] = userId.split('@');\n const user = users.find(u => u.metadata.name === name);\n\n if (user) return user.spec.profile?.displayName;\n return userId;\n};\n\nconst getUser = (users: UserEntity[], userId: string) => {\n const [name] = userId.split('@');\n\n return users.find(u => u.metadata.name === name);\n};\n\nexport const getScheduleItems = (\n availability: InfiniteData<ScheduleInformation[], unknown> | undefined,\n groupIndexMap?: Map<number, number>,\n) => {\n return availability\n ? availability.pages\n .flatMap(p => p)\n // @ts-ignore\n .flatMap((a, i) =>\n // @ts-ignore\n a.scheduleItems\n // @ts-ignore\n ?.filter(scheduleItem => scheduleItem.status === 'oof')\n // @ts-ignore\n .map(s => ({\n id: Date.now().toString(36) + Math.random().toString(36).slice(2),\n group: groupIndexMap?.get(i) ?? i,\n start_time: dayjs(s.start?.dateTime!),\n end_time: dayjs(s.end?.dateTime!),\n canMove: false,\n canResize: false,\n })),\n )\n .filter(isTimeLineItem)\n : [];\n};\n\nexport const getGroups = (\n availability: InfiniteData<ScheduleInformation[], unknown> | undefined,\n isUserEntity: string | false,\n users: UserEntityV1alpha1[] | undefined,\n): [\n groups: Array<{\n id: number;\n highlight: boolean;\n title: string;\n entity?: UserEntity;\n height: number;\n }>,\n groupIndexMap: Map<number, number>,\n] => {\n if (!availability) {\n return [[], new Map()];\n }\n\n const flattenedSchedules = availability.pages\n .flatMap(p => p)\n .map((a, originalIndex) => ({\n originalIndex,\n schedule: a,\n title: getFullName(users || [], a.scheduleId || ''),\n }));\n\n // Sort by title (display name) alphabetically\n const sortedSchedules = [...flattenedSchedules].sort((a, b) => {\n const titleA = a.title || '';\n const titleB = b.title || '';\n return titleA.localeCompare(titleB);\n });\n\n // Create mapping from original index to new sorted index\n const groupIndexMap = new Map(\n sortedSchedules.map((item, newIndex) => [item.originalIndex, newIndex]),\n );\n\n const groups = sortedSchedules.map((item, newIndex) => {\n const isHighlighted =\n isUserEntity &&\n item.schedule.scheduleId &&\n isUserEntity === item.schedule.scheduleId?.split('@')[0];\n\n return {\n id: newIndex,\n highlight: !!isHighlighted,\n title: item.title || '',\n entity: getUser(users || [], item.schedule.scheduleId || ''),\n height: 30,\n };\n });\n\n return [groups, groupIndexMap];\n};\n"],"names":[],"mappings":";;AAMA,MAAM,cAAA,GAAiB,CACrB,IAAA,KACkC;AAClC,EAAA,OAAO,IAAA,KAAS,MAAA;AAClB,CAAA;AAEA,MAAM,WAAA,GAAc,CAAC,KAAA,EAAqB,MAAA,KAAmB;AAC3D,EAAA,MAAM,CAAC,IAAI,CAAA,GAAI,MAAA,CAAO,MAAM,GAAG,CAAA;AAC/B,EAAA,MAAM,OAAO,KAAA,CAAM,IAAA,CAAK,OAAK,CAAA,CAAE,QAAA,CAAS,SAAS,IAAI,CAAA;AAErD,EAAA,IAAI,IAAA,EAAM,OAAO,IAAA,CAAK,IAAA,CAAK,OAAA,EAAS,WAAA;AACpC,EAAA,OAAO,MAAA;AACT,CAAA;AAEA,MAAM,OAAA,GAAU,CAAC,KAAA,EAAqB,MAAA,KAAmB;AACvD,EAAA,MAAM,CAAC,IAAI,CAAA,GAAI,MAAA,CAAO,MAAM,GAAG,CAAA;AAE/B,EAAA,OAAO,MAAM,IAAA,CAAK,CAAA,CAAA,KAAK,CAAA,CAAE,QAAA,CAAS,SAAS,IAAI,CAAA;AACjD,CAAA;AAEO,MAAM,gBAAA,GAAmB,CAC9B,YAAA,EACA,aAAA,KACG;AACH,EAAA,OAAO,eACH,YAAA,CAAa,KAAA,CACV,OAAA,CAAQ,CAAA,CAAA,KAAK,CAAC,CAAA,CAEd,OAAA;AAAA,IAAQ,CAAC,CAAA,EAAG,CAAA;AAAA;AAAA,MAEX,CAAA,CAAE,eAEE,MAAA,CAAO,CAAA,YAAA,KAAgB,aAAa,MAAA,KAAW,KAAK,CAAA,CAErD,GAAA,CAAI,CAAA,CAAA,MAAM;AAAA,QACT,EAAA,EAAI,IAAA,CAAK,GAAA,EAAI,CAAE,SAAS,EAAE,CAAA,GAAI,IAAA,CAAK,MAAA,EAAO,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,MAAM,CAAC,CAAA;AAAA,QAChE,KAAA,EAAO,aAAA,EAAe,GAAA,CAAI,CAAC,CAAA,IAAK,CAAA;AAAA,QAChC,UAAA,EAAY,KAAA,CAAM,CAAA,CAAE,KAAA,EAAO,QAAS,CAAA;AAAA,QACpC,QAAA,EAAU,KAAA,CAAM,CAAA,CAAE,GAAA,EAAK,QAAS,CAAA;AAAA,QAChC,OAAA,EAAS,KAAA;AAAA,QACT,SAAA,EAAW;AAAA,OACb,CAAE;AAAA;AAAA,GACN,CACC,MAAA,CAAO,cAAc,CAAA,GACxB,EAAC;AACP;AAEO,MAAM,SAAA,GAAY,CACvB,YAAA,EACA,YAAA,EACA,KAAA,KAUG;AACH,EAAA,IAAI,CAAC,YAAA,EAAc;AACjB,IAAA,OAAO,CAAC,EAAC,kBAAG,IAAI,KAAK,CAAA;AAAA,EACvB;AAEA,EAAA,MAAM,kBAAA,GAAqB,YAAA,CAAa,KAAA,CACrC,OAAA,CAAQ,CAAA,CAAA,KAAK,CAAC,CAAA,CACd,GAAA,CAAI,CAAC,CAAA,EAAG,aAAA,MAAmB;AAAA,IAC1B,aAAA;AAAA,IACA,QAAA,EAAU,CAAA;AAAA,IACV,OAAO,WAAA,CAAY,KAAA,IAAS,EAAC,EAAG,CAAA,CAAE,cAAc,EAAE;AAAA,GACpD,CAAE,CAAA;AAGJ,EAAA,MAAM,eAAA,GAAkB,CAAC,GAAG,kBAAkB,EAAE,IAAA,CAAK,CAAC,GAAG,CAAA,KAAM;AAC7D,IAAA,MAAM,MAAA,GAAS,EAAE,KAAA,IAAS,EAAA;AAC1B,IAAA,MAAM,MAAA,GAAS,EAAE,KAAA,IAAS,EAAA;AAC1B,IAAA,OAAO,MAAA,CAAO,cAAc,MAAM,CAAA;AAAA,EACpC,CAAC,CAAA;AAGD,EAAA,MAAM,gBAAgB,IAAI,GAAA;AAAA,IACxB,eAAA,CAAgB,IAAI,CAAC,IAAA,EAAM,aAAa,CAAC,IAAA,CAAK,aAAA,EAAe,QAAQ,CAAC;AAAA,GACxE;AAEA,EAAA,MAAM,MAAA,GAAS,eAAA,CAAgB,GAAA,CAAI,CAAC,MAAM,QAAA,KAAa;AACrD,IAAA,MAAM,aAAA,GACJ,YAAA,IACA,IAAA,CAAK,QAAA,CAAS,UAAA,IACd,YAAA,KAAiB,IAAA,CAAK,QAAA,CAAS,UAAA,EAAY,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA;AAEzD,IAAA,OAAO;AAAA,MACL,EAAA,EAAI,QAAA;AAAA,MACJ,SAAA,EAAW,CAAC,CAAC,aAAA;AAAA,MACb,KAAA,EAAO,KAAK,KAAA,IAAS,EAAA;AAAA,MACrB,MAAA,EAAQ,QAAQ,KAAA,IAAS,IAAI,IAAA,CAAK,QAAA,CAAS,cAAc,EAAE,CAAA;AAAA,MAC3D,MAAA,EAAQ;AAAA,KACV;AAAA,EACF,CAAC,CAAA;AAED,EAAA,OAAO,CAAC,QAAQ,aAAa,CAAA;AAC/B;;;;"}
@@ -1,24 +1,31 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
- import { AdapterLuxon } from '@mui/x-date-pickers/AdapterLuxon';
3
- import FormControl from '@mui/material/FormControl';
4
- import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
5
- import { DesktopDatePicker } from '@mui/x-date-pickers/DesktopDatePicker';
2
+ import { DatePicker } from '@backstage/ui';
3
+ import { parseDate } from '@internationalized/date';
4
+ import dayjs from 'dayjs';
6
5
 
6
+ function toDateValue(date) {
7
+ return parseDate(date.format("YYYY-MM-DD"));
8
+ }
7
9
  const DateSelector = ({
8
10
  label,
9
- initalDate,
11
+ initialDate,
10
12
  onDateChange
11
13
  }) => {
12
- return /* @__PURE__ */ jsx(FormControl, { variant: "standard", children: /* @__PURE__ */ jsx(LocalizationProvider, { dateAdapter: AdapterLuxon, children: /* @__PURE__ */ jsx(
13
- DesktopDatePicker,
14
+ const handleChange = (value) => {
15
+ if (value) {
16
+ onDateChange(dayjs(value.toString()));
17
+ } else {
18
+ onDateChange(null);
19
+ }
20
+ };
21
+ return /* @__PURE__ */ jsx(
22
+ DatePicker,
14
23
  {
15
- format: "yyyy-MM-dd",
16
24
  label,
17
- value: initalDate,
18
- defaultValue: initalDate,
19
- onChange: onDateChange
25
+ value: toDateValue(initialDate),
26
+ onChange: handleChange
20
27
  }
21
- ) }) });
28
+ );
22
29
  };
23
30
 
24
31
  export { DateSelector };
@@ -1 +1 @@
1
- {"version":3,"file":"DateSelector.esm.js","sources":["../../../src/components/DateSelector/DateSelector.tsx"],"sourcesContent":["import { DateTime } from 'luxon/src/datetime';\nimport { AdapterLuxon } from '@mui/x-date-pickers/AdapterLuxon';\nimport FormControl from '@mui/material/FormControl';\nimport { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';\nimport { DesktopDatePicker } from '@mui/x-date-pickers/DesktopDatePicker';\n\ntype DateSelectorProps = {\n label: string;\n initalDate: DateTime;\n onDateChange: (date: DateTime | null | string | undefined) => void;\n};\n\nexport const DateSelector = ({\n label,\n initalDate,\n onDateChange,\n}: DateSelectorProps) => {\n return (\n <FormControl variant=\"standard\">\n <LocalizationProvider dateAdapter={AdapterLuxon}>\n <DesktopDatePicker\n format=\"yyyy-MM-dd\"\n label={label}\n value={initalDate}\n defaultValue={initalDate}\n onChange={onDateChange}\n />\n </LocalizationProvider>\n </FormControl>\n );\n};\n"],"names":[],"mappings":";;;;;;AAYO,MAAM,eAAe,CAAC;AAAA,EAC3B,KAAA;AAAA,EACA,UAAA;AAAA,EACA;AACF,CAAA,KAAyB;AACvB,EAAA,2BACG,WAAA,EAAA,EAAY,OAAA,EAAQ,YACnB,QAAA,kBAAA,GAAA,CAAC,oBAAA,EAAA,EAAqB,aAAa,YAAA,EACjC,QAAA,kBAAA,GAAA;AAAA,IAAC,iBAAA;AAAA,IAAA;AAAA,MACC,MAAA,EAAO,YAAA;AAAA,MACP,KAAA;AAAA,MACA,KAAA,EAAO,UAAA;AAAA,MACP,YAAA,EAAc,UAAA;AAAA,MACd,QAAA,EAAU;AAAA;AAAA,KAEd,CAAA,EACF,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"DateSelector.esm.js","sources":["../../../src/components/DateSelector/DateSelector.tsx"],"sourcesContent":["import { DatePicker } from '@backstage/ui';\nimport { parseDate, type DateValue } from '@internationalized/date';\nimport dayjs, { type Dayjs } from 'dayjs';\n\ntype DateSelectorProps = {\n label: string;\n initialDate: Dayjs;\n onDateChange: (date: Dayjs | null) => void;\n};\n\nfunction toDateValue(date: Dayjs): DateValue {\n return parseDate(date.format('YYYY-MM-DD'));\n}\n\nexport const DateSelector = ({\n label,\n initialDate,\n onDateChange,\n}: DateSelectorProps) => {\n const handleChange = (value: DateValue | null) => {\n if (value) {\n onDateChange(dayjs(value.toString()));\n } else {\n onDateChange(null);\n }\n };\n\n return (\n <DatePicker\n label={label}\n value={toDateValue(initialDate)}\n onChange={handleChange}\n />\n );\n};\n"],"names":[],"mappings":";;;;;AAUA,SAAS,YAAY,IAAA,EAAwB;AAC3C,EAAA,OAAO,SAAA,CAAU,IAAA,CAAK,MAAA,CAAO,YAAY,CAAC,CAAA;AAC5C;AAEO,MAAM,eAAe,CAAC;AAAA,EAC3B,KAAA;AAAA,EACA,WAAA;AAAA,EACA;AACF,CAAA,KAAyB;AACvB,EAAA,MAAM,YAAA,GAAe,CAAC,KAAA,KAA4B;AAChD,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,YAAA,CAAa,KAAA,CAAM,KAAA,CAAM,QAAA,EAAU,CAAC,CAAA;AAAA,IACtC,CAAA,MAAO;AACL,MAAA,YAAA,CAAa,IAAI,CAAA;AAAA,IACnB;AAAA,EACF,CAAA;AAEA,EAAA,uBACE,GAAA;AAAA,IAAC,UAAA;AAAA,IAAA;AAAA,MACC,KAAA;AAAA,MACA,KAAA,EAAO,YAAY,WAAW,CAAA;AAAA,MAC9B,QAAA,EAAU;AAAA;AAAA,GACZ;AAEJ;;;;"}
@@ -1,27 +1,30 @@
1
1
  import { useInfiniteQuery } from '@tanstack/react-query';
2
2
  import { useApi } from '@backstage/core-plugin-api';
3
- import { slice } from 'lodash';
4
3
  import { vacationCalendarApiRef } from '../api/VacationCalendarApi.esm.js';
5
4
  import '@backstage/errors';
6
5
 
7
6
  const PAGE_SIZE = 20;
7
+ const GRAPH_DATE_TIME_FORMAT = "YYYY-MM-DDTHH:mm:ss.SSSZ";
8
8
  const useAvailability = (users, startDate, endDate, isSignedIn) => {
9
9
  const calendarApi = useApi(vacationCalendarApiRef);
10
10
  const {
11
- data: availablity,
11
+ data: availability,
12
12
  error,
13
13
  isLoading: isAvailabilityLoading,
14
14
  isFetching: isAvailabilityFetching,
15
15
  hasNextPage,
16
16
  fetchNextPage
17
17
  } = useInfiniteQuery({
18
- queryFn: ({ pageParam = 0 }) => {
19
- const currentUsers = slice(users || [], pageParam, pageParam + PAGE_SIZE);
18
+ queryFn: ({ pageParam }) => {
19
+ const currentUsers = (users || []).slice(
20
+ pageParam,
21
+ pageParam + PAGE_SIZE
22
+ );
20
23
  return calendarApi.getAvailability(
21
24
  {
22
25
  users: currentUsers?.map((u) => u.spec.profile?.email ?? "") || [],
23
- startDateTime: startDate.toISO(),
24
- endDateTime: endDate.toISO()
26
+ startDateTime: startDate.format(GRAPH_DATE_TIME_FORMAT),
27
+ endDateTime: endDate.format(GRAPH_DATE_TIME_FORMAT)
25
28
  },
26
29
  {
27
30
  Prefer: 'outlook.timezone="Europe/Stockholm"'
@@ -31,9 +34,10 @@ const useAvailability = (users, startDate, endDate, isSignedIn) => {
31
34
  queryKey: [
32
35
  "calendarAvailability",
33
36
  users,
34
- startDate.toISO(),
35
- endDate.toISO()
37
+ startDate.format(GRAPH_DATE_TIME_FORMAT),
38
+ endDate.format(GRAPH_DATE_TIME_FORMAT)
36
39
  ],
40
+ initialPageParam: 0,
37
41
  getNextPageParam: (_, allPages) => {
38
42
  const numberOfUsers = allPages.flatMap((p) => p).length;
39
43
  if (numberOfUsers === users?.length) {
@@ -41,8 +45,8 @@ const useAvailability = (users, startDate, endDate, isSignedIn) => {
41
45
  }
42
46
  return numberOfUsers;
43
47
  },
44
- cacheTime: 3e4 * 1e3,
45
- enabled: isSignedIn && startDate.isValid && endDate.isValid && !!users,
48
+ gcTime: 3e4 * 1e3,
49
+ enabled: isSignedIn && startDate.isValid() && endDate.isValid() && !!users,
46
50
  retry: false,
47
51
  refetchInterval: 3e4 * 1e3,
48
52
  refetchIntervalInBackground: false,
@@ -50,7 +54,7 @@ const useAvailability = (users, startDate, endDate, isSignedIn) => {
50
54
  refetchOnReconnect: false
51
55
  });
52
56
  return {
53
- availablity,
57
+ availability,
54
58
  error,
55
59
  isLoading: isAvailabilityLoading,
56
60
  isFetching: isAvailabilityFetching,
@@ -1 +1 @@
1
- {"version":3,"file":"useAvailibility.esm.js","sources":["../../src/hooks/useAvailibility.ts"],"sourcesContent":["import { useInfiniteQuery } from '@tanstack/react-query';\nimport { UserEntityV1alpha1 } from '@backstage/catalog-model';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { slice } from 'lodash';\nimport { DateTime } from 'luxon';\nimport { vacationCalendarApiRef } from '../api';\n\nconst PAGE_SIZE = 20;\n\nexport const useAvailability = (\n users: UserEntityV1alpha1[] | undefined,\n startDate: DateTime<true>,\n endDate: DateTime<true>,\n isSignedIn: boolean,\n) => {\n const calendarApi = useApi(vacationCalendarApiRef);\n const {\n data: availablity,\n error,\n isLoading: isAvailabilityLoading,\n isFetching: isAvailabilityFetching,\n hasNextPage,\n fetchNextPage,\n } = useInfiniteQuery({\n queryFn: ({ pageParam = 0 }) => {\n const currentUsers = slice(users || [], pageParam, pageParam + PAGE_SIZE);\n\n return calendarApi.getAvailability(\n {\n users: currentUsers?.map(u => u.spec.profile?.email ?? '') || [],\n startDateTime: startDate.toISO(),\n endDateTime: endDate.toISO(),\n },\n {\n Prefer: 'outlook.timezone=\"Europe/Stockholm\"',\n },\n );\n },\n queryKey: [\n 'calendarAvailability',\n users,\n startDate.toISO(),\n endDate.toISO(),\n ],\n getNextPageParam: (_, allPages) => {\n const numberOfUsers = allPages.flatMap(p => p).length;\n if (numberOfUsers === users?.length) {\n return undefined;\n }\n // This will be starting index to fetch the next batch.\n return numberOfUsers;\n },\n cacheTime: 30000 * 1000,\n enabled: isSignedIn && startDate.isValid && endDate.isValid && !!users,\n retry: false,\n refetchInterval: 30000 * 1000,\n refetchIntervalInBackground: false,\n refetchOnWindowFocus: false,\n refetchOnReconnect: false,\n });\n return {\n availablity,\n error,\n isLoading: isAvailabilityLoading,\n isFetching: isAvailabilityFetching,\n hasNextPage,\n fetchNextPage,\n };\n};\n"],"names":[],"mappings":";;;;;;AAOA,MAAM,SAAA,GAAY,EAAA;AAEX,MAAM,eAAA,GAAkB,CAC7B,KAAA,EACA,SAAA,EACA,SACA,UAAA,KACG;AACH,EAAA,MAAM,WAAA,GAAc,OAAO,sBAAsB,CAAA;AACjD,EAAA,MAAM;AAAA,IACJ,IAAA,EAAM,WAAA;AAAA,IACN,KAAA;AAAA,IACA,SAAA,EAAW,qBAAA;AAAA,IACX,UAAA,EAAY,sBAAA;AAAA,IACZ,WAAA;AAAA,IACA;AAAA,MACE,gBAAA,CAAiB;AAAA,IACnB,OAAA,EAAS,CAAC,EAAE,SAAA,GAAY,GAAE,KAAM;AAC9B,MAAA,MAAM,eAAe,KAAA,CAAM,KAAA,IAAS,EAAC,EAAG,SAAA,EAAW,YAAY,SAAS,CAAA;AAExE,MAAA,OAAO,WAAA,CAAY,eAAA;AAAA,QACjB;AAAA,UACE,KAAA,EAAO,YAAA,EAAc,GAAA,CAAI,CAAA,CAAA,KAAK,CAAA,CAAE,KAAK,OAAA,EAAS,KAAA,IAAS,EAAE,CAAA,IAAK,EAAC;AAAA,UAC/D,aAAA,EAAe,UAAU,KAAA,EAAM;AAAA,UAC/B,WAAA,EAAa,QAAQ,KAAA;AAAM,SAC7B;AAAA,QACA;AAAA,UACE,MAAA,EAAQ;AAAA;AACV,OACF;AAAA,IACF,CAAA;AAAA,IACA,QAAA,EAAU;AAAA,MACR,sBAAA;AAAA,MACA,KAAA;AAAA,MACA,UAAU,KAAA,EAAM;AAAA,MAChB,QAAQ,KAAA;AAAM,KAChB;AAAA,IACA,gBAAA,EAAkB,CAAC,CAAA,EAAG,QAAA,KAAa;AACjC,MAAA,MAAM,aAAA,GAAgB,QAAA,CAAS,OAAA,CAAQ,CAAA,CAAA,KAAK,CAAC,CAAA,CAAE,MAAA;AAC/C,MAAA,IAAI,aAAA,KAAkB,OAAO,MAAA,EAAQ;AACnC,QAAA,OAAO,MAAA;AAAA,MACT;AAEA,MAAA,OAAO,aAAA;AAAA,IACT,CAAA;AAAA,IACA,WAAW,GAAA,GAAQ,GAAA;AAAA,IACnB,SAAS,UAAA,IAAc,SAAA,CAAU,WAAW,OAAA,CAAQ,OAAA,IAAW,CAAC,CAAC,KAAA;AAAA,IACjE,KAAA,EAAO,KAAA;AAAA,IACP,iBAAiB,GAAA,GAAQ,GAAA;AAAA,IACzB,2BAAA,EAA6B,KAAA;AAAA,IAC7B,oBAAA,EAAsB,KAAA;AAAA,IACtB,kBAAA,EAAoB;AAAA,GACrB,CAAA;AACD,EAAA,OAAO;AAAA,IACL,WAAA;AAAA,IACA,KAAA;AAAA,IACA,SAAA,EAAW,qBAAA;AAAA,IACX,UAAA,EAAY,sBAAA;AAAA,IACZ,WAAA;AAAA,IACA;AAAA,GACF;AACF;;;;"}
1
+ {"version":3,"file":"useAvailibility.esm.js","sources":["../../src/hooks/useAvailibility.ts"],"sourcesContent":["import { useInfiniteQuery } from '@tanstack/react-query';\nimport { UserEntityV1alpha1 } from '@backstage/catalog-model';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { type Dayjs } from 'dayjs';\nimport { vacationCalendarApiRef } from '../api';\n\nconst PAGE_SIZE = 20;\nconst GRAPH_DATE_TIME_FORMAT = 'YYYY-MM-DDTHH:mm:ss.SSSZ';\n\nexport const useAvailability = (\n users: UserEntityV1alpha1[] | undefined,\n startDate: Dayjs,\n endDate: Dayjs,\n isSignedIn: boolean,\n) => {\n const calendarApi = useApi(vacationCalendarApiRef);\n const {\n data: availability,\n error,\n isLoading: isAvailabilityLoading,\n isFetching: isAvailabilityFetching,\n hasNextPage,\n fetchNextPage,\n } = useInfiniteQuery({\n queryFn: ({ pageParam }) => {\n const currentUsers = (users || []).slice(\n pageParam,\n pageParam + PAGE_SIZE,\n );\n\n return calendarApi.getAvailability(\n {\n users: currentUsers?.map(u => u.spec.profile?.email ?? '') || [],\n startDateTime: startDate.format(GRAPH_DATE_TIME_FORMAT),\n endDateTime: endDate.format(GRAPH_DATE_TIME_FORMAT),\n },\n {\n Prefer: 'outlook.timezone=\"Europe/Stockholm\"',\n },\n );\n },\n queryKey: [\n 'calendarAvailability',\n users,\n startDate.format(GRAPH_DATE_TIME_FORMAT),\n endDate.format(GRAPH_DATE_TIME_FORMAT),\n ],\n initialPageParam: 0,\n getNextPageParam: (_, allPages) => {\n const numberOfUsers = allPages.flatMap(p => p).length;\n if (numberOfUsers === users?.length) {\n return undefined;\n }\n // This will be starting index to fetch the next batch.\n return numberOfUsers;\n },\n gcTime: 30000 * 1000,\n enabled: isSignedIn && startDate.isValid() && endDate.isValid() && !!users,\n retry: false,\n refetchInterval: 30000 * 1000,\n refetchIntervalInBackground: false,\n refetchOnWindowFocus: false,\n refetchOnReconnect: false,\n });\n return {\n availability,\n error,\n isLoading: isAvailabilityLoading,\n isFetching: isAvailabilityFetching,\n hasNextPage,\n fetchNextPage,\n };\n};\n"],"names":[],"mappings":";;;;;AAMA,MAAM,SAAA,GAAY,EAAA;AAClB,MAAM,sBAAA,GAAyB,0BAAA;AAExB,MAAM,eAAA,GAAkB,CAC7B,KAAA,EACA,SAAA,EACA,SACA,UAAA,KACG;AACH,EAAA,MAAM,WAAA,GAAc,OAAO,sBAAsB,CAAA;AACjD,EAAA,MAAM;AAAA,IACJ,IAAA,EAAM,YAAA;AAAA,IACN,KAAA;AAAA,IACA,SAAA,EAAW,qBAAA;AAAA,IACX,UAAA,EAAY,sBAAA;AAAA,IACZ,WAAA;AAAA,IACA;AAAA,MACE,gBAAA,CAAiB;AAAA,IACnB,OAAA,EAAS,CAAC,EAAE,SAAA,EAAU,KAAM;AAC1B,MAAA,MAAM,YAAA,GAAA,CAAgB,KAAA,IAAS,EAAC,EAAG,KAAA;AAAA,QACjC,SAAA;AAAA,QACA,SAAA,GAAY;AAAA,OACd;AAEA,MAAA,OAAO,WAAA,CAAY,eAAA;AAAA,QACjB;AAAA,UACE,KAAA,EAAO,YAAA,EAAc,GAAA,CAAI,CAAA,CAAA,KAAK,CAAA,CAAE,KAAK,OAAA,EAAS,KAAA,IAAS,EAAE,CAAA,IAAK,EAAC;AAAA,UAC/D,aAAA,EAAe,SAAA,CAAU,MAAA,CAAO,sBAAsB,CAAA;AAAA,UACtD,WAAA,EAAa,OAAA,CAAQ,MAAA,CAAO,sBAAsB;AAAA,SACpD;AAAA,QACA;AAAA,UACE,MAAA,EAAQ;AAAA;AACV,OACF;AAAA,IACF,CAAA;AAAA,IACA,QAAA,EAAU;AAAA,MACR,sBAAA;AAAA,MACA,KAAA;AAAA,MACA,SAAA,CAAU,OAAO,sBAAsB,CAAA;AAAA,MACvC,OAAA,CAAQ,OAAO,sBAAsB;AAAA,KACvC;AAAA,IACA,gBAAA,EAAkB,CAAA;AAAA,IAClB,gBAAA,EAAkB,CAAC,CAAA,EAAG,QAAA,KAAa;AACjC,MAAA,MAAM,aAAA,GAAgB,QAAA,CAAS,OAAA,CAAQ,CAAA,CAAA,KAAK,CAAC,CAAA,CAAE,MAAA;AAC/C,MAAA,IAAI,aAAA,KAAkB,OAAO,MAAA,EAAQ;AACnC,QAAA,OAAO,MAAA;AAAA,MACT;AAEA,MAAA,OAAO,aAAA;AAAA,IACT,CAAA;AAAA,IACA,QAAQ,GAAA,GAAQ,GAAA;AAAA,IAChB,OAAA,EAAS,cAAc,SAAA,CAAU,OAAA,MAAa,OAAA,CAAQ,OAAA,EAAQ,IAAK,CAAC,CAAC,KAAA;AAAA,IACrE,KAAA,EAAO,KAAA;AAAA,IACP,iBAAiB,GAAA,GAAQ,GAAA;AAAA,IACzB,2BAAA,EAA6B,KAAA;AAAA,IAC7B,oBAAA,EAAsB,KAAA;AAAA,IACtB,kBAAA,EAAoB;AAAA,GACrB,CAAA;AACD,EAAA,OAAO;AAAA,IACL,YAAA;AAAA,IACA,KAAA;AAAA,IACA,SAAA,EAAW,qBAAA;AAAA,IACX,UAAA,EAAY,sBAAA;AAAA,IACZ,WAAA;AAAA,IACA;AAAA,GACF;AACF;;;;"}
@@ -0,0 +1,29 @@
1
+ function styleInject(css, ref) {
2
+ if ( ref === void 0 ) ref = {};
3
+ var insertAt = ref.insertAt;
4
+
5
+ if (typeof document === 'undefined') { return; }
6
+
7
+ var head = document.head || document.getElementsByTagName('head')[0];
8
+ var style = document.createElement('style');
9
+ style.type = 'text/css';
10
+
11
+ if (insertAt === 'top') {
12
+ if (head.firstChild) {
13
+ head.insertBefore(style, head.firstChild);
14
+ } else {
15
+ head.appendChild(style);
16
+ }
17
+ } else {
18
+ head.appendChild(style);
19
+ }
20
+
21
+ if (style.styleSheet) {
22
+ style.styleSheet.cssText = css;
23
+ } else {
24
+ style.appendChild(document.createTextNode(css));
25
+ }
26
+ }
27
+
28
+ export { styleInject as default };
29
+ //# sourceMappingURL=style-inject.es.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"style-inject.es.esm.js","sources":["../../../../../../node_modules/style-inject/dist/style-inject.es.js"],"sourcesContent":["function styleInject(css, ref) {\n if ( ref === void 0 ) ref = {};\n var insertAt = ref.insertAt;\n\n if (!css || typeof document === 'undefined') { return; }\n\n var head = document.head || document.getElementsByTagName('head')[0];\n var style = document.createElement('style');\n style.type = 'text/css';\n\n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild);\n } else {\n head.appendChild(style);\n }\n } else {\n head.appendChild(style);\n }\n\n if (style.styleSheet) {\n style.styleSheet.cssText = css;\n } else {\n style.appendChild(document.createTextNode(css));\n }\n}\n\nexport default styleInject;\n"],"names":[],"mappings":"AAAA,SAAS,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE;AAC/B,EAAE,KAAK,GAAG,KAAK,MAAM,GAAG,GAAG,GAAG,EAAE;AAChC,EAAE,IAAI,QAAQ,GAAG,GAAG,CAAC,QAAQ;;AAE7B,EAAE,IAAY,OAAO,QAAQ,KAAK,WAAW,EAAE,EAAE,OAAO,CAAC;;AAEzD,EAAE,IAAI,IAAI,GAAG,QAAQ,CAAC,IAAI,IAAI,QAAQ,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACtE,EAAE,IAAI,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC;AAC7C,EAAE,KAAK,CAAC,IAAI,GAAG,UAAU;;AAEzB,EAAE,IAAI,QAAQ,KAAK,KAAK,EAAE;AAC1B,IAAI,IAAI,IAAI,CAAC,UAAU,EAAE;AACzB,MAAM,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,CAAC;AAC/C,IAAI,CAAC,MAAM;AACX,MAAM,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;AAC7B,IAAI;AACJ,EAAE,CAAC,MAAM;AACT,IAAI,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;AAC3B,EAAE;;AAEF,EAAE,IAAI,KAAK,CAAC,UAAU,EAAE;AACxB,IAAI,KAAK,CAAC,UAAU,CAAC,OAAO,GAAG,GAAG;AAClC,EAAE,CAAC,MAAM;AACT,IAAI,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;AACnD,EAAE;AACF;;;;","x_google_ignoreList":[0]}
@@ -1,4 +1,3 @@
1
- import 'react-calendar-timeline/lib/Timeline.css';
2
1
  import { createPlugin, createApiFactory, fetchApiRef, microsoftAuthApiRef, createRoutableExtension } from '@backstage/core-plugin-api';
3
2
  import { rootRouteRef } from './routes.esm.js';
4
3
  import { vacationCalendarApiRef } from './api/VacationCalendarApi.esm.js';
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.esm.js","sources":["../src/plugin.ts"],"sourcesContent":["import 'react-calendar-timeline/lib/Timeline.css';\nimport {\n createApiFactory,\n createPlugin,\n createRoutableExtension,\n fetchApiRef,\n microsoftAuthApiRef,\n} from '@backstage/core-plugin-api';\nimport { rootRouteRef } from './routes';\nimport { VacationCalendarApiClient, vacationCalendarApiRef } from './api';\n\n/**\n * Plugin that provides the VacationCalendar api\n * @public */\nexport const vacationCalendarPlugin = createPlugin({\n id: 'vacation-calendar',\n apis: [\n createApiFactory({\n api: vacationCalendarApiRef,\n deps: {\n authApi: microsoftAuthApiRef,\n fetchApi: fetchApiRef,\n },\n factory: ({ authApi, fetchApi }) =>\n new VacationCalendarApiClient({ authApi, fetchApi }),\n }),\n ],\n routes: {\n root: rootRouteRef,\n },\n});\n\n/**\n * Routable extension for VacationCalendarPage\n * @public\n */\nexport const VacationCalendarPage = vacationCalendarPlugin.provide(\n createRoutableExtension({\n name: 'VacationCalendarPage',\n component: () => import('./components').then(m => m.VacationCalendar),\n mountPoint: rootRouteRef,\n }),\n);\n"],"names":[],"mappings":";;;;;;AAcO,MAAM,yBAAyB,YAAA,CAAa;AAAA,EACjD,EAAA,EAAI,mBAAA;AAAA,EACJ,IAAA,EAAM;AAAA,IACJ,gBAAA,CAAiB;AAAA,MACf,GAAA,EAAK,sBAAA;AAAA,MACL,IAAA,EAAM;AAAA,QACJ,OAAA,EAAS,mBAAA;AAAA,QACT,QAAA,EAAU;AAAA,OACZ;AAAA,MACA,OAAA,EAAS,CAAC,EAAE,OAAA,EAAS,QAAA,EAAS,KAC5B,IAAI,yBAAA,CAA0B,EAAE,OAAA,EAAS,QAAA,EAAU;AAAA,KACtD;AAAA,GACH;AAAA,EACA,MAAA,EAAQ;AAAA,IACN,IAAA,EAAM;AAAA;AAEV,CAAC;AAMM,MAAM,uBAAuB,sBAAA,CAAuB,OAAA;AAAA,EACzD,uBAAA,CAAwB;AAAA,IACtB,IAAA,EAAM,sBAAA;AAAA,IACN,SAAA,EAAW,MAAM,OAAO,2BAAc,EAAE,IAAA,CAAK,CAAA,CAAA,KAAK,EAAE,gBAAgB,CAAA;AAAA,IACpE,UAAA,EAAY;AAAA,GACb;AACH;;;;"}
1
+ {"version":3,"file":"plugin.esm.js","sources":["../src/plugin.ts"],"sourcesContent":["import {\n createApiFactory,\n createPlugin,\n createRoutableExtension,\n fetchApiRef,\n microsoftAuthApiRef,\n} from '@backstage/core-plugin-api';\nimport { rootRouteRef } from './routes';\nimport { VacationCalendarApiClient, vacationCalendarApiRef } from './api';\n\n/**\n * Plugin that provides the VacationCalendar api\n * @public */\nexport const vacationCalendarPlugin = createPlugin({\n id: 'vacation-calendar',\n apis: [\n createApiFactory({\n api: vacationCalendarApiRef,\n deps: {\n authApi: microsoftAuthApiRef,\n fetchApi: fetchApiRef,\n },\n factory: ({ authApi, fetchApi }) =>\n new VacationCalendarApiClient({ authApi, fetchApi }),\n }),\n ],\n routes: {\n root: rootRouteRef,\n },\n});\n\n/**\n * Routable extension for VacationCalendarPage\n * @public\n */\nexport const VacationCalendarPage = vacationCalendarPlugin.provide(\n createRoutableExtension({\n name: 'VacationCalendarPage',\n component: () => import('./components').then(m => m.VacationCalendar),\n mountPoint: rootRouteRef,\n }),\n);\n"],"names":[],"mappings":";;;;;AAaO,MAAM,yBAAyB,YAAA,CAAa;AAAA,EACjD,EAAA,EAAI,mBAAA;AAAA,EACJ,IAAA,EAAM;AAAA,IACJ,gBAAA,CAAiB;AAAA,MACf,GAAA,EAAK,sBAAA;AAAA,MACL,IAAA,EAAM;AAAA,QACJ,OAAA,EAAS,mBAAA;AAAA,QACT,QAAA,EAAU;AAAA,OACZ;AAAA,MACA,OAAA,EAAS,CAAC,EAAE,OAAA,EAAS,QAAA,EAAS,KAC5B,IAAI,yBAAA,CAA0B,EAAE,OAAA,EAAS,QAAA,EAAU;AAAA,KACtD;AAAA,GACH;AAAA,EACA,MAAA,EAAQ;AAAA,IACN,IAAA,EAAM;AAAA;AAEV,CAAC;AAMM,MAAM,uBAAuB,sBAAA,CAAuB,OAAA;AAAA,EACzD,uBAAA,CAAwB;AAAA,IACtB,IAAA,EAAM,sBAAA;AAAA,IACN,SAAA,EAAW,MAAM,OAAO,2BAAc,EAAE,IAAA,CAAK,CAAA,CAAA,KAAK,EAAE,gBAAgB,CAAA;AAAA,IACpE,UAAA,EAAY;AAAA,GACb;AACH;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axis-backstage/plugin-vacation-calendar",
3
- "version": "0.10.1",
3
+ "version": "0.11.1",
4
4
  "exports": {
5
5
  ".": {
6
6
  "import": "./dist/index.esm.js",
@@ -44,7 +44,10 @@
44
44
  "./alpha": "@backstage/FrontendPlugin"
45
45
  }
46
46
  },
47
- "sideEffects": false,
47
+ "sideEffects": [
48
+ "**/*.css",
49
+ "**/*.css.esm.js"
50
+ ],
48
51
  "scripts": {
49
52
  "start": "backstage-cli package start",
50
53
  "build": "backstage-cli package build",
@@ -55,27 +58,20 @@
55
58
  "postpack": "backstage-cli package postpack"
56
59
  },
57
60
  "dependencies": {
58
- "@backstage/catalog-model": "^1.8.0",
59
- "@backstage/core-components": "^0.18.9",
60
- "@backstage/core-plugin-api": "^1.12.5",
61
- "@backstage/errors": "^1.3.0",
62
- "@backstage/frontend-plugin-api": "^0.16.2",
63
- "@backstage/plugin-catalog-react": "^2.1.4",
64
- "@backstage/theme": "^0.7.3",
65
- "@date-io/luxon": "3.0.0",
66
- "@material-ui/core": "^4.12.4",
67
- "@material-ui/pickers": "^3.3.11",
61
+ "@backstage/catalog-model": "^1.9.0",
62
+ "@backstage/core-components": "^0.18.11",
63
+ "@backstage/core-plugin-api": "^1.12.7",
64
+ "@backstage/errors": "^1.3.1",
65
+ "@backstage/frontend-plugin-api": "^0.17.2",
66
+ "@backstage/plugin-catalog-react": "^3.1.0",
67
+ "@backstage/ui": "^0.16.0",
68
+ "@internationalized/date": "^3.12.2",
68
69
  "@microsoft/microsoft-graph-types": "^2.40.0",
69
- "@mui/lab": "^5.0.0-alpha.170",
70
70
  "@mui/material": "^5.15.20",
71
- "@mui/x-date-pickers": "^7.7.0",
72
- "@tanstack/react-query": "4.29.1",
71
+ "@tanstack/react-query": "^5.101.0",
72
+ "dayjs": "^1.11.10",
73
73
  "interactjs": "^1.10.27",
74
- "lodash": "^4.18.1",
75
- "luxon": "^3.4.4",
76
- "moment": "^2.30.1",
77
- "prop-types": "^15.8.1",
78
- "react-calendar-timeline": "^0.28.0",
74
+ "react-calendar-timeline": "^0.30.0-beta.4",
79
75
  "react-use": "^17.5.0"
80
76
  },
81
77
  "peerDependencies": {
@@ -85,18 +81,15 @@
85
81
  "react-router-dom": "^6.3.0"
86
82
  },
87
83
  "devDependencies": {
88
- "@backstage/catalog-client": "^1.15.0",
89
- "@backstage/cli": "^0.36.1",
90
- "@backstage/core-app-api": "^1.20.0",
91
- "@backstage/dev-utils": "^1.1.22",
92
- "@backstage/test-utils": "^1.7.17",
84
+ "@backstage/catalog-client": "^1.16.0",
85
+ "@backstage/cli": "^0.36.3",
86
+ "@backstage/core-app-api": "^1.20.2",
87
+ "@backstage/dev-utils": "^1.1.24",
88
+ "@backstage/test-utils": "^1.7.19",
93
89
  "@testing-library/dom": "^10.0.0",
94
90
  "@testing-library/jest-dom": "^6.0.0",
95
91
  "@testing-library/react": "^16.0.0",
96
- "@testing-library/user-event": "^14.5.2",
97
- "@types/lodash": "^4.17.5",
98
- "@types/luxon": "^3.4.2",
99
- "@types/react-calendar-timeline": "^0.28.6"
92
+ "@testing-library/user-event": "^14.5.2"
100
93
  },
101
94
  "files": [
102
95
  "dist"