@axis-backstage/plugin-vacation-calendar 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/README.md +110 -0
  2. package/dist/api/VacationCalendarApi.esm.js +8 -0
  3. package/dist/api/VacationCalendarApi.esm.js.map +1 -0
  4. package/dist/api/VacationCalendarClient.esm.js +101 -0
  5. package/dist/api/VacationCalendarClient.esm.js.map +1 -0
  6. package/dist/components/CalendarCard/CalendarCard.esm.js +203 -0
  7. package/dist/components/CalendarCard/CalendarCard.esm.js.map +1 -0
  8. package/dist/components/CalendarCard/fetch.esm.js +33 -0
  9. package/dist/components/CalendarCard/fetch.esm.js.map +1 -0
  10. package/dist/components/CalendarCard/lib.esm.js +46 -0
  11. package/dist/components/CalendarCard/lib.esm.js.map +1 -0
  12. package/dist/components/DateSelector/DateSelector.esm.js +25 -0
  13. package/dist/components/DateSelector/DateSelector.esm.js.map +1 -0
  14. package/dist/components/SignInContent/SignInContent.esm.js +33 -0
  15. package/dist/components/SignInContent/SignInContent.esm.js.map +1 -0
  16. package/dist/components/VacationCalendar.esm.js +11 -0
  17. package/dist/components/VacationCalendar.esm.js.map +1 -0
  18. package/dist/components/index.esm.js +4 -0
  19. package/dist/components/index.esm.js.map +1 -0
  20. package/dist/hooks/useAvailibility.esm.js +63 -0
  21. package/dist/hooks/useAvailibility.esm.js.map +1 -0
  22. package/dist/hooks/useSignIn.esm.js +23 -0
  23. package/dist/hooks/useSignIn.esm.js.map +1 -0
  24. package/dist/index.d.ts +84 -0
  25. package/dist/index.esm.js +4 -0
  26. package/dist/index.esm.js.map +1 -0
  27. package/dist/plugin.esm.js +32 -0
  28. package/dist/plugin.esm.js.map +1 -0
  29. package/dist/routes.esm.js +8 -0
  30. package/dist/routes.esm.js.map +1 -0
  31. package/package.json +71 -0
package/README.md ADDED
@@ -0,0 +1,110 @@
1
+ # Vacation Calendar plugin
2
+
3
+ Welcome to the Vacation Calendar plugin!
4
+
5
+ ![calendar-year-light-example](https://github.com/AxisCommunications/backstage-plugins/blob/main/plugins/vacation-calendar/media/year-light.png)
6
+ ![calendar-year-dark-example](https://github.com/AxisCommunications/backstage-plugins/blob/main/plugins/vacation-calendar/media/year-dark.png)
7
+
8
+ ## Introduction
9
+
10
+ The Vacation Calendar plugin allows you to get a comprehensive overview of your colleagues' vacations and out-of-office events. Clearly see when your vacations overlap or which team members will be present on specific occasions, making your life and teamwork easier and more efficient.
11
+
12
+ Our plugin is based on [Microsoft-Calendar Plugin](https://github.com/backstage/community-plugins/tree/main/workspaces/microsoft-calendar/plugins/microsoft-calendar) with modifications for focusing on multiple users' calendars. Full credit to them for their great plugin!
13
+
14
+ ## How it works
15
+
16
+ The plugin interacts with the Microsoft Graph API to fetch users' calendars and schedule items. Mark your events as Out of Office in either the Outlook client or the Teams client. By marking your events as "Out of Office," they will be correctly reflected in the Vacation Calendar plugin, providing an accurate overview of your availability.
17
+
18
+ ## Autentication
19
+
20
+ The Vacation Calendar plugin requires Microsoft authentication. If you have not set this up, please follow the upstream guide on Microsoft authentication: [Backstage.io Microsoft Authentication Guide](https://backstage.io/docs/auth/microsoft/provider/).
21
+
22
+ At present, the plugin supports only Microsoft authentication and does not integrate with other Backstage authentication methods. If you need the plugin to support a different authentication method, please create an issue so we can discuss your requirements.
23
+
24
+ ## Getting started
25
+
26
+ 1. First, install the plugin into your app:
27
+
28
+ ```bash
29
+ # From your Backstage root directory
30
+ yarn --cwd packages/app add @axis-backstage/plugin-vacation-calendar
31
+ ```
32
+
33
+ 2. Setup the API-factory.
34
+
35
+ ```ts
36
+ // packages/app/src/apis.ts:
37
+
38
+ createApiFactory({
39
+ api: vacationCalendarApiRef,
40
+ deps: {
41
+ authApi: microsoftAuthApiRef,
42
+ fetchApi: fetchApiRef,
43
+ },
44
+ factory: ({ authApi, fetchApi }) =>
45
+ new VacationCalendarApiClient({ authApi, fetchApi }),
46
+ }),
47
+
48
+ ```
49
+
50
+ 3. Modify your entity page to include the `VacationCalendarPage` component:
51
+
52
+ ```tsx
53
+ // In packages/app/src/components/catalog/EntityPage.tsx
54
+ import { VacationCalendarPage } from '@axis-backstage/plugin-vacation-calendar';
55
+
56
+ const groupPage = (
57
+ <EntityLayout>
58
+ <EntityLayout.Route path="/vacation-calendar" title="Out Of Office">
59
+ <Grid md={6}>
60
+ <VacationCalendarPage />
61
+ </Grid>
62
+ </EntityLayout.Route>
63
+ </EntityLayout>
64
+ );
65
+ ```
66
+
67
+ By doing this, all Backstage users who are part of that group will be displayed in the `Out of Office` tab on the group's entity page.
68
+
69
+ ## Integration with the Catalog
70
+
71
+ To fetch all colleagues with the same manager for a user entity, add the manager annotation to the entity's **catalog-info.yaml** file:
72
+
73
+ ```yaml
74
+ apiVersion: backstage.io/v1alpha1
75
+ kind: User
76
+ metadata:
77
+ # ...
78
+ annotations:
79
+ manager: value # The Backstage username of the mananger
80
+ ```
81
+
82
+ If the manager annotation is set, you can display all users with the same manager for a user entity. To do this, add the `VacationCalendarPage` component to the entity page for users:
83
+
84
+ ```tsx
85
+ // In packages/app/src/components/catalog/EntityPage.tsx
86
+ import { VacationCalendarPage } from '@axis-backstage/plugin-vacation-calendar';
87
+
88
+ const userPage = (
89
+ <EntityLayout>
90
+ <EntityLayout.Route path="/vacation-calendar" title="Out Of Office">
91
+ <Grid md={6}>
92
+ <VacationCalendarPage />
93
+ </Grid>
94
+ </EntityLayout.Route>
95
+ </EntityLayout>
96
+ );
97
+ ```
98
+
99
+ ## Development
100
+
101
+ The plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn start` in the root directory, and then navigating to [/vacation-calendar](http://localhost:3000/vacation-calendar).
102
+
103
+ You can also serve the plugin in isolation by running `yarn start` in the plugin directory.
104
+ This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads.
105
+ It is only meant for local development, and the setup for it can be found inside the [/dev](./dev) directory.
106
+
107
+ ## Screenshots
108
+
109
+ ![calendar-month-light-example](https://github.com/AxisCommunications/backstage-plugins/blob/main/plugins/vacation-calendar/media/month-light.png)
110
+ ![calendar-month-dark-example](https://github.com/AxisCommunications/backstage-plugins/blob/main/plugins/vacation-calendar/media/month-dark.png)
@@ -0,0 +1,8 @@
1
+ import { createApiRef } from '@backstage/core-plugin-api';
2
+
3
+ const vacationCalendarApiRef = createApiRef({
4
+ id: "plugin.vacation-calendar.service"
5
+ });
6
+
7
+ export { vacationCalendarApiRef };
8
+ //# sourceMappingURL=VacationCalendarApi.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VacationCalendarApi.esm.js","sources":["../../src/api/VacationCalendarApi.ts"],"sourcesContent":["import { createApiRef } from '@backstage/core-plugin-api';\nimport type { MicrosoftCalendar, ScheduleInformation } from './types';\n\n/**\n * The apiref for the VacationCalendar plugin.\n *\n * @public\n */\nexport const vacationCalendarApiRef = createApiRef<VacationCalendarApi>({\n id: 'plugin.vacation-calendar.service',\n});\n\n/**\n * The definition for the VacationCalendar api.\n *\n * @public\n */\nexport interface VacationCalendarApi {\n /**\n * Fetches schedule items for users\n */\n getCalendars(): Promise<MicrosoftCalendar[]>;\n /**\n * Fetches Microsoft calendars\n */\n getAvailability(\n params: {\n users: string[];\n startDateTime: string;\n endDateTime: string;\n },\n headers: {\n [x: string]: any;\n },\n ): Promise<ScheduleInformation[]>;\n}\n"],"names":[],"mappings":";;AAQO,MAAM,yBAAyB,YAAkC,CAAA;AAAA,EACtE,EAAI,EAAA,kCAAA;AACN,CAAC;;;;"}
@@ -0,0 +1,101 @@
1
+ import { ResponseError } from '@backstage/errors';
2
+
3
+ const getAvailabilityBody = ({
4
+ users,
5
+ startDateTime,
6
+ endDateTime
7
+ }) => ({
8
+ Schedules: users,
9
+ StartTime: {
10
+ dateTime: startDateTime,
11
+ timeZone: "Europe/Paris"
12
+ },
13
+ EndTime: {
14
+ dateTime: endDateTime,
15
+ timeZone: "Europe/Paris"
16
+ },
17
+ availabilityViewInterval: "1440"
18
+ });
19
+ class VacationCalendarApiClient {
20
+ authApi;
21
+ fetchApi;
22
+ constructor(options) {
23
+ this.authApi = options.authApi;
24
+ this.fetchApi = options.fetchApi;
25
+ }
26
+ async get(path, params = {}, headers) {
27
+ const query = new URLSearchParams(params);
28
+ const url = new URL(
29
+ `${path}?${query.toString()}`,
30
+ "https://graph.microsoft.com"
31
+ );
32
+ const token = await this.authApi.getAccessToken();
33
+ let temp = {};
34
+ if (headers && typeof headers === "object") {
35
+ temp = {
36
+ ...headers
37
+ };
38
+ }
39
+ if (token) {
40
+ temp.Authorization = `Bearer ${token}`;
41
+ }
42
+ const response = await this.fetchApi.fetch(url.toString(), {
43
+ headers: temp
44
+ });
45
+ if (!response.ok) {
46
+ throw await ResponseError.fromResponse(response);
47
+ }
48
+ return response.json();
49
+ }
50
+ async post(path, body, headers) {
51
+ const url = new URL(path, "https://graph.microsoft.com");
52
+ const token = await this.authApi.getAccessToken();
53
+ let temp = {};
54
+ if (headers && typeof headers === "object") {
55
+ temp = {
56
+ ...headers
57
+ };
58
+ }
59
+ if (token) {
60
+ temp.Authorization = `Bearer ${token}`;
61
+ }
62
+ temp["Content-type"] = "application/json";
63
+ const response = await this.fetchApi.fetch(url.toString(), {
64
+ method: "POST",
65
+ headers: temp,
66
+ body: JSON.stringify(body)
67
+ });
68
+ if (!response.ok) {
69
+ throw await ResponseError.fromResponse(response);
70
+ }
71
+ return response.json();
72
+ }
73
+ /**
74
+ * Fetches Microsoft calendars
75
+ *
76
+ * @returns the MicrosoftValendar objects
77
+ */
78
+ async getCalendars() {
79
+ const data = await this.get("v1.0/me/calendars");
80
+ return data.value;
81
+ }
82
+ /**
83
+ * Fetches schedule items for users
84
+ *
85
+ * @param users - list of users
86
+ * @param startDateTime - string with start date
87
+ * @param endDateTime - string with end date
88
+ * @returns Microsoft ScheduleInformation items
89
+ */
90
+ async getAvailability(params, headers) {
91
+ const data = await this.post(
92
+ `v1.0/me/calendar/getschedule`,
93
+ getAvailabilityBody({ ...params }),
94
+ headers
95
+ );
96
+ return data.value;
97
+ }
98
+ }
99
+
100
+ export { VacationCalendarApiClient };
101
+ //# sourceMappingURL=VacationCalendarClient.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VacationCalendarClient.esm.js","sources":["../../src/api/VacationCalendarClient.ts"],"sourcesContent":["import { OAuthApi, FetchApi } from '@backstage/core-plugin-api';\nimport { ResponseError } from '@backstage/errors';\nimport type { ScheduleInformation, MicrosoftCalendar } from './types';\n\nconst getAvailabilityBody = ({\n users,\n startDateTime,\n endDateTime,\n}: {\n users: string[];\n startDateTime: string;\n endDateTime: string;\n}) => ({\n Schedules: users,\n StartTime: {\n dateTime: startDateTime,\n timeZone: 'Europe/Paris',\n },\n EndTime: {\n dateTime: endDateTime,\n timeZone: 'Europe/Paris',\n },\n availabilityViewInterval: '1440',\n});\n\n/**\n * The client implementation for the frontend api.\n *\n * @public\n */\nexport class VacationCalendarApiClient {\n private readonly authApi: OAuthApi;\n private readonly fetchApi: FetchApi;\n\n constructor(options: { authApi: OAuthApi; fetchApi: FetchApi }) {\n this.authApi = options.authApi;\n this.fetchApi = options.fetchApi;\n }\n\n private async get<T>(\n path: string,\n params: { [key in string]: any } = {},\n headers?: any,\n ): Promise<T> {\n const query = new URLSearchParams(params);\n const url = new URL(\n `${path}?${query.toString()}`,\n 'https://graph.microsoft.com',\n );\n const token = await this.authApi.getAccessToken();\n let temp: any = {};\n\n if (headers && typeof headers === 'object') {\n temp = {\n ...headers,\n };\n }\n\n if (token) {\n temp.Authorization = `Bearer ${token}`;\n }\n\n const response = await this.fetchApi.fetch(url.toString(), {\n headers: temp,\n });\n\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n\n return response.json() as Promise<T>;\n }\n\n private async post<T>(path: string, body: any, headers?: any): Promise<T> {\n const url = new URL(path, 'https://graph.microsoft.com');\n const token = await this.authApi.getAccessToken();\n let temp: any = {};\n\n if (headers && typeof headers === 'object') {\n temp = {\n ...headers,\n };\n }\n\n if (token) {\n temp.Authorization = `Bearer ${token}`;\n }\n temp['Content-type'] = 'application/json';\n\n const response = await this.fetchApi.fetch(url.toString(), {\n method: 'POST',\n headers: temp,\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n\n return response.json() as Promise<T>;\n }\n\n /**\n * Fetches Microsoft calendars\n *\n * @returns the MicrosoftValendar objects\n */\n async getCalendars(): Promise<MicrosoftCalendar[]> {\n const data = await this.get<{\n id: string;\n value: MicrosoftCalendar[];\n }>('v1.0/me/calendars');\n return data.value;\n }\n\n /**\n * Fetches schedule items for users\n *\n * @param users - list of users\n * @param startDateTime - string with start date\n * @param endDateTime - string with end date\n * @returns Microsoft ScheduleInformation items\n */\n async getAvailability(\n params: {\n users: string[];\n startDateTime: string;\n endDateTime: string;\n },\n headers: { [key in string]: any },\n ): Promise<ScheduleInformation[]> {\n const data = await this.post<{\n id: string;\n value: ScheduleInformation[];\n }>(\n `v1.0/me/calendar/getschedule`,\n getAvailabilityBody({ ...params }),\n headers,\n );\n return data.value;\n }\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,203 @@
1
+ import React, { useState } from 'react';
2
+ import useAsync from 'react-use/lib/useAsync';
3
+ import Timeline, { TimelineHeaders, SidebarHeader, DateHeader } from 'react-calendar-timeline';
4
+ import { DateTime } from 'luxon';
5
+ import { useApi } from '@backstage/core-plugin-api';
6
+ import { useEntity, catalogApiRef } from '@backstage/plugin-catalog-react';
7
+ import { ErrorPanel, Content, ContentHeader, SupportButton, Progress, Link, Avatar } from '@backstage/core-components';
8
+ import { DateSelector } from '../DateSelector/DateSelector.esm.js';
9
+ import { getGroups, getScheduleItems } from './lib.esm.js';
10
+ import { fetchUserEntities, fetchGroupEntities } from './fetch.esm.js';
11
+ import { useAvailability } from '../../hooks/useAvailibility.esm.js';
12
+ import { useSignIn } from '../../hooks/useSignIn.esm.js';
13
+ import { SignInContent } from '../SignInContent/SignInContent.esm.js';
14
+ import MuiLink from '@mui/material/Link';
15
+ import Button from '@mui/material/Button';
16
+ import Box from '@mui/material/Box';
17
+ import Typography from '@mui/material/Typography';
18
+ import Stack from '@mui/material/Stack';
19
+
20
+ const DEFAULT_NUM_DAYS = 60;
21
+ const IntervalDateHeader = (props) => {
22
+ return /* @__PURE__ */ React.createElement(
23
+ MuiLink,
24
+ {
25
+ sx: {
26
+ display: "flex",
27
+ alignItems: "center",
28
+ justifyContent: "center",
29
+ height: "100%",
30
+ borderBottom: "1px solid #bbb",
31
+ cursor: "pointer",
32
+ fontSize: "14px",
33
+ borderLeft: "2px solid #bbb",
34
+ color: (theme) => theme.palette.text.primary,
35
+ position: "absolute",
36
+ width: props?.intervalContext.interval.labelWidth,
37
+ left: props?.intervalContext.interval.left
38
+ },
39
+ onClick: props?.getIntervalProps().onClick
40
+ },
41
+ props?.intervalContext.intervalText
42
+ );
43
+ };
44
+ const CalendarCard = () => {
45
+ const { entity } = useEntity();
46
+ const catalogApi = useApi(catalogApiRef);
47
+ const [startDate, setStartDate] = useState(DateTime.now());
48
+ const [endDate, setEndDate] = useState(
49
+ DateTime.now().endOf("day").plus({ days: DEFAULT_NUM_DAYS })
50
+ );
51
+ const { isSignedIn, isInitialized, signIn } = useSignIn();
52
+ useAsync(async () => signIn(true), [signIn]);
53
+ const isUserEntity = entity.kind.toLowerCase() === "user" && entity.metadata.name;
54
+ const { value: users } = useAsync(async () => {
55
+ return isUserEntity ? fetchUserEntities(catalogApi, entity) : fetchGroupEntities(catalogApi, entity);
56
+ }, [catalogApi, entity]);
57
+ const {
58
+ availablity,
59
+ error,
60
+ isLoading: isAvailabilityLoading,
61
+ isFetching: isAvailabilityFetching,
62
+ hasNextPage,
63
+ fetchNextPage
64
+ } = useAvailability(users, startDate, endDate, isSignedIn);
65
+ const showLoader = isAvailabilityLoading || isAvailabilityFetching || !isInitialized;
66
+ const groups = getGroups(availablity, isUserEntity, users);
67
+ const scheduleItems = getScheduleItems(availablity);
68
+ if (users?.length === 0) {
69
+ return /* @__PURE__ */ React.createElement(
70
+ ErrorPanel,
71
+ {
72
+ title: "No users found.",
73
+ defaultExpanded: true,
74
+ error: Error("No users found for current entity.")
75
+ }
76
+ );
77
+ }
78
+ if (error instanceof Error) {
79
+ return /* @__PURE__ */ React.createElement(
80
+ ErrorPanel,
81
+ {
82
+ title: "Microsoft Graph Error.",
83
+ defaultExpanded: true,
84
+ error
85
+ }
86
+ );
87
+ }
88
+ return /* @__PURE__ */ React.createElement(Content, null, /* @__PURE__ */ React.createElement(ContentHeader, { title: "Out of Office Calendar" }, /* @__PURE__ */ React.createElement(SupportButton, { title: "Backstage Out Of Office Calendar" }, /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Typography, { variant: "h6" }, "How it works"), /* @__PURE__ */ React.createElement(Typography, null, 'The "Out of Office"-calendar shows Away events. If you want your calendar events to be seen in the "Out of Office"-calendar, be sure to mark your presence as "Away" in outlook.'), /* @__PURE__ */ React.createElement(Typography, { variant: "h6" }, "Limitations"), /* @__PURE__ */ React.createElement(Typography, null, "Due to limitations in the Microsoft Graph API the maximum range of the dates is ", DEFAULT_NUM_DAYS, " days.")))), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Stack, { direction: "row", gap: 3, alignItems: "center" }, /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(
89
+ DateSelector,
90
+ {
91
+ onDateChange: (d) => {
92
+ if (d instanceof DateTime) {
93
+ const { days } = endDate.diff(d, "days").toObject();
94
+ if (days && Math.abs(days) > DEFAULT_NUM_DAYS) {
95
+ setEndDate(d.endOf("day").plus({ days: DEFAULT_NUM_DAYS }));
96
+ }
97
+ setStartDate(d);
98
+ }
99
+ },
100
+ initalDate: startDate,
101
+ label: "Start Date"
102
+ }
103
+ )), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(
104
+ DateSelector,
105
+ {
106
+ onDateChange: (d) => {
107
+ if (d instanceof DateTime) {
108
+ const { days } = startDate.diff(d, "days").toObject();
109
+ if (days && Math.abs(days) > DEFAULT_NUM_DAYS) {
110
+ setStartDate(
111
+ d.endOf("day").minus({ days: DEFAULT_NUM_DAYS })
112
+ );
113
+ }
114
+ setEndDate(d);
115
+ }
116
+ },
117
+ initalDate: endDate,
118
+ label: "End Date"
119
+ }
120
+ )), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(
121
+ Button,
122
+ {
123
+ onClick: () => {
124
+ fetchNextPage();
125
+ },
126
+ disabled: showLoader || !hasNextPage,
127
+ variant: "contained",
128
+ color: "primary"
129
+ },
130
+ "Show more Users"
131
+ ))), showLoader && /* @__PURE__ */ React.createElement(Box, { py: 2 }, /* @__PURE__ */ React.createElement(Progress, { variant: "query" })), !isSignedIn && isInitialized && /* @__PURE__ */ React.createElement(Box, { p: 1, pb: 0, minHeight: 200, maxHeight: 602, overflow: "auto" }, /* @__PURE__ */ React.createElement(SignInContent, { handleAuthClick: () => signIn(false) })), !isAvailabilityLoading && isSignedIn && /* @__PURE__ */ React.createElement(Box, { mt: 3, pb: 0, minHeight: 200, overflow: "auto" }, /* @__PURE__ */ React.createElement(
132
+ Timeline,
133
+ {
134
+ groups,
135
+ sidebarWidth: 250,
136
+ groupRenderer: ({ group }) => {
137
+ return /* @__PURE__ */ React.createElement(
138
+ Link,
139
+ {
140
+ to: `/catalog/default/user/${group.entity?.metadata.name}`
141
+ },
142
+ /* @__PURE__ */ React.createElement(
143
+ "div",
144
+ {
145
+ className: "custom-group",
146
+ style: {
147
+ background: group.highlight ? "linear-gradient(90deg, #FFCC33A0, transparent 100%)" : "",
148
+ marginLeft: "-4px",
149
+ paddingLeft: "4px",
150
+ display: "flex",
151
+ whiteSpace: "nowrap",
152
+ flexWrap: "nowrap",
153
+ flexDirection: "row",
154
+ gap: "5px"
155
+ }
156
+ },
157
+ /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(
158
+ Avatar,
159
+ {
160
+ displayName: group.entity?.metadata.displayName,
161
+ picture: group.entity?.spec.profile?.picture,
162
+ customStyles: {
163
+ width: 30,
164
+ height: 30
165
+ }
166
+ }
167
+ )),
168
+ /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("span", { className: "title" }, group.title))
169
+ )
170
+ );
171
+ },
172
+ items: scheduleItems,
173
+ itemTouchSendsClick: false,
174
+ defaultTimeStart: startDate.toJSDate(),
175
+ defaultTimeEnd: endDate.toJSDate()
176
+ },
177
+ /* @__PURE__ */ React.createElement(
178
+ TimelineHeaders,
179
+ {
180
+ style: {
181
+ backgroundColor: "transparent",
182
+ color: "black",
183
+ position: "sticky",
184
+ top: "-6px"
185
+ }
186
+ },
187
+ /* @__PURE__ */ React.createElement(SidebarHeader, null, ({ getRootProps }) => {
188
+ return /* @__PURE__ */ React.createElement("div", { ...getRootProps() });
189
+ }),
190
+ /* @__PURE__ */ React.createElement(
191
+ DateHeader,
192
+ {
193
+ unit: "primaryHeader",
194
+ intervalRenderer: IntervalDateHeader
195
+ }
196
+ ),
197
+ /* @__PURE__ */ React.createElement(DateHeader, { intervalRenderer: IntervalDateHeader })
198
+ )
199
+ ))));
200
+ };
201
+
202
+ export { CalendarCard };
203
+ //# sourceMappingURL=CalendarCard.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CalendarCard.esm.js","sources":["../../../src/components/CalendarCard/CalendarCard.tsx"],"sourcesContent":["import React, { 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 = getGroups(availablity, isUserEntity, users);\n const scheduleItems = getScheduleItems(availablity);\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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"}
@@ -0,0 +1,33 @@
1
+ import { stringifyEntityRef, DEFAULT_NAMESPACE } from '@backstage/catalog-model';
2
+
3
+ const MANAGER_ANNOTATION = "manager";
4
+ const fetchUserEntities = async (catalogApi, entity) => {
5
+ if (!entity.metadata?.annotations?.[MANAGER_ANNOTATION]) {
6
+ return [entity];
7
+ }
8
+ const filter = {
9
+ kind: "User",
10
+ [`metadata.annotations.${MANAGER_ANNOTATION}`]: entity.metadata.annotations[MANAGER_ANNOTATION]
11
+ };
12
+ const { items } = await catalogApi.getEntities({ filter });
13
+ return items;
14
+ };
15
+ const fetchGroupEntities = async (catalogApi, entity) => {
16
+ const {
17
+ metadata: { name: groupName, namespace = DEFAULT_NAMESPACE }
18
+ } = entity;
19
+ const filter = {
20
+ kind: "User",
21
+ "relations.memberof": [
22
+ stringifyEntityRef({
23
+ kind: "group",
24
+ namespace: namespace.toLocaleLowerCase("en-US"),
25
+ name: groupName.toLocaleLowerCase("en-US")
26
+ })
27
+ ]
28
+ };
29
+ return (await catalogApi.getEntities({ filter })).items;
30
+ };
31
+
32
+ export { fetchGroupEntities, fetchUserEntities };
33
+ //# sourceMappingURL=fetch.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch.esm.js","sources":["../../../src/components/CalendarCard/fetch.ts"],"sourcesContent":["import {\n DEFAULT_NAMESPACE,\n Entity,\n UserEntity,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { CatalogApi } from '@backstage/plugin-catalog-react';\n\nconst MANAGER_ANNOTATION = 'manager';\n\nexport const fetchUserEntities = async (\n catalogApi: CatalogApi,\n entity: Entity,\n) => {\n if (!entity.metadata?.annotations?.[MANAGER_ANNOTATION]) {\n return [entity as UserEntity];\n }\n\n const filter = {\n kind: 'User',\n [`metadata.annotations.${MANAGER_ANNOTATION}`]:\n entity.metadata.annotations[MANAGER_ANNOTATION],\n };\n\n const { items } = await catalogApi.getEntities({ filter });\n return items as UserEntity[];\n};\n\nexport const fetchGroupEntities = async (\n catalogApi: CatalogApi,\n entity: Entity,\n) => {\n const {\n metadata: { name: groupName, namespace = DEFAULT_NAMESPACE },\n } = entity;\n\n const filter = {\n kind: 'User',\n 'relations.memberof': [\n stringifyEntityRef({\n kind: 'group',\n namespace: namespace.toLocaleLowerCase('en-US'),\n name: groupName.toLocaleLowerCase('en-US'),\n }),\n ],\n };\n\n return (await catalogApi.getEntities({ filter })).items as UserEntity[];\n};\n"],"names":[],"mappings":";;AAQA,MAAM,kBAAqB,GAAA,SAAA,CAAA;AAEd,MAAA,iBAAA,GAAoB,OAC/B,UAAA,EACA,MACG,KAAA;AACH,EAAA,IAAI,CAAC,MAAA,CAAO,QAAU,EAAA,WAAA,GAAc,kBAAkB,CAAG,EAAA;AACvD,IAAA,OAAO,CAAC,MAAoB,CAAA,CAAA;AAAA,GAC9B;AAEA,EAAA,MAAM,MAAS,GAAA;AAAA,IACb,IAAM,EAAA,MAAA;AAAA,IACN,CAAC,wBAAwB,kBAAkB,CAAA,CAAE,GAC3C,MAAO,CAAA,QAAA,CAAS,YAAY,kBAAkB,CAAA;AAAA,GAClD,CAAA;AAEA,EAAM,MAAA,EAAE,OAAU,GAAA,MAAM,WAAW,WAAY,CAAA,EAAE,QAAQ,CAAA,CAAA;AACzD,EAAO,OAAA,KAAA,CAAA;AACT,EAAA;AAEa,MAAA,kBAAA,GAAqB,OAChC,UAAA,EACA,MACG,KAAA;AACH,EAAM,MAAA;AAAA,IACJ,QAAU,EAAA,EAAE,IAAM,EAAA,SAAA,EAAW,YAAY,iBAAkB,EAAA;AAAA,GACzD,GAAA,MAAA,CAAA;AAEJ,EAAA,MAAM,MAAS,GAAA;AAAA,IACb,IAAM,EAAA,MAAA;AAAA,IACN,oBAAsB,EAAA;AAAA,MACpB,kBAAmB,CAAA;AAAA,QACjB,IAAM,EAAA,OAAA;AAAA,QACN,SAAA,EAAW,SAAU,CAAA,iBAAA,CAAkB,OAAO,CAAA;AAAA,QAC9C,IAAA,EAAM,SAAU,CAAA,iBAAA,CAAkB,OAAO,CAAA;AAAA,OAC1C,CAAA;AAAA,KACH;AAAA,GACF,CAAA;AAEA,EAAA,OAAA,CAAQ,MAAM,UAAW,CAAA,WAAA,CAAY,EAAE,MAAA,EAAQ,CAAG,EAAA,KAAA,CAAA;AACpD;;;;"}
@@ -0,0 +1,46 @@
1
+ import { head } from 'lodash';
2
+ import { DateTime } from 'luxon';
3
+
4
+ const isTimeLineItem = (item) => {
5
+ return item !== void 0;
6
+ };
7
+ const getFullName = (users, userId) => {
8
+ const name = head(userId.split("@"));
9
+ const user = users.find((u) => u.metadata.name === name);
10
+ if (user)
11
+ return user.spec.profile?.displayName;
12
+ return userId;
13
+ };
14
+ const getUser = (users, userId) => {
15
+ const name = head(userId.split("@"));
16
+ const user = users.find((u) => u.metadata.name === name);
17
+ return user;
18
+ };
19
+ const getScheduleItems = (availablity) => {
20
+ return availablity ? availablity?.pages.flatMap((p) => p).flatMap(
21
+ (a, i) => (
22
+ // @ts-ignore
23
+ a.scheduleItems?.filter((scheduleItem) => scheduleItem.status === "oof").map((s) => ({
24
+ id: Date.now().toString(36) + Math.random().toString(36).slice(2),
25
+ group: i,
26
+ start_time: DateTime.fromISO(s.start?.dateTime),
27
+ end_time: DateTime.fromISO(s.end?.dateTime),
28
+ canMove: false,
29
+ canResize: false
30
+ }))
31
+ )
32
+ ).filter(isTimeLineItem) : [];
33
+ };
34
+ const getGroups = (availablity, isUserEntity, users) => {
35
+ return availablity ? availablity.pages.flatMap((p) => p).map((a, i) => ({
36
+ id: i,
37
+ // @ts-ignore
38
+ highlight: isUserEntity && a.scheduleId && isUserEntity === head(a.scheduleId.split("@")),
39
+ title: getFullName(users || [], a.scheduleId || ""),
40
+ entity: getUser(users || [], a.scheduleId || ""),
41
+ height: 30
42
+ })) : [];
43
+ };
44
+
45
+ export { getGroups, getScheduleItems };
46
+ //# sourceMappingURL=lib.esm.js.map
@@ -0,0 +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) => {\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: 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 return availablity\n ? availablity.pages\n .flatMap(p => p)\n .map((a, i) => ({\n id: i,\n // @ts-ignore\n highlight:\n isUserEntity &&\n a.scheduleId &&\n isUserEntity === head(a.scheduleId.split('@')),\n title: getFullName(users || [], a.scheduleId || ''),\n entity: getUser(users || [], a.scheduleId || ''),\n height: 30,\n }))\n : [];\n};\n"],"names":[],"mappings":";;;AAOA,MAAM,cAAA,GAAiB,CACrB,IACkC,KAAA;AAClC,EAAA,OAAO,IAAS,KAAA,KAAA,CAAA,CAAA;AAClB,CAAA,CAAA;AAEA,MAAM,WAAA,GAAc,CAAC,KAAA,EAAqB,MAAmB,KAAA;AAC3D,EAAA,MAAM,IAAO,GAAA,IAAA,CAAK,MAAO,CAAA,KAAA,CAAM,GAAG,CAAC,CAAA,CAAA;AACnC,EAAA,MAAM,OAAO,KAAM,CAAA,IAAA,CAAK,OAAK,CAAE,CAAA,QAAA,CAAS,SAAS,IAAI,CAAA,CAAA;AAErD,EAAI,IAAA,IAAA;AAAM,IAAO,OAAA,IAAA,CAAK,KAAK,OAAS,EAAA,WAAA,CAAA;AACpC,EAAO,OAAA,MAAA,CAAA;AACT,CAAA,CAAA;AAEA,MAAM,OAAA,GAAU,CAAC,KAAA,EAAqB,MAAmB,KAAA;AACvD,EAAA,MAAM,IAAO,GAAA,IAAA,CAAK,MAAO,CAAA,KAAA,CAAM,GAAG,CAAC,CAAA,CAAA;AACnC,EAAA,MAAM,OAAO,KAAM,CAAA,IAAA,CAAK,OAAK,CAAE,CAAA,QAAA,CAAS,SAAS,IAAI,CAAA,CAAA;AAErD,EAAO,OAAA,IAAA,CAAA;AACT,CAAA,CAAA;AAEa,MAAA,gBAAA,GAAmB,CAC9B,WACG,KAAA;AACH,EAAA,OAAO,cACH,WAAa,EAAA,KAAA,CACV,OAAQ,CAAA,CAAA,CAAA,KAAK,CAAC,CAEd,CAAA,OAAA;AAAA,IAAQ,CAAC,CAAG,EAAA,CAAA;AAAA;AAAA,MAEX,CAAA,CAAE,eAEE,MAAO,CAAA,CAAA,YAAA,KAAgB,aAAa,MAAW,KAAA,KAAK,CAErD,CAAA,GAAA,CAAI,CAAM,CAAA,MAAA;AAAA,QACT,EAAI,EAAA,IAAA,CAAK,GAAI,EAAA,CAAE,SAAS,EAAE,CAAA,GAAI,IAAK,CAAA,MAAA,EAAS,CAAA,QAAA,CAAS,EAAE,CAAA,CAAE,MAAM,CAAC,CAAA;AAAA,QAChE,KAAO,EAAA,CAAA;AAAA,QACP,UAAY,EAAA,QAAA,CAAS,OAAQ,CAAA,CAAA,CAAE,OAAO,QAAS,CAAA;AAAA,QAC/C,QAAU,EAAA,QAAA,CAAS,OAAQ,CAAA,CAAA,CAAE,KAAK,QAAS,CAAA;AAAA,QAC3C,OAAS,EAAA,KAAA;AAAA,QACT,SAAW,EAAA,KAAA;AAAA,OACX,CAAA,CAAA;AAAA,KAAA;AAAA,GAEL,CAAA,MAAA,CAAO,cAAc,CAAA,GACxB,EAAC,CAAA;AACP,EAAA;AAEO,MAAM,SAAY,GAAA,CACvB,WACA,EAAA,YAAA,EACA,KACG,KAAA;AACH,EAAO,OAAA,WAAA,GACH,WAAY,CAAA,KAAA,CACT,OAAQ,CAAA,CAAA,CAAA,KAAK,CAAC,CACd,CAAA,GAAA,CAAI,CAAC,CAAA,EAAG,CAAO,MAAA;AAAA,IACd,EAAI,EAAA,CAAA;AAAA;AAAA,IAEJ,SAAA,EACE,YACA,IAAA,CAAA,CAAE,UACF,IAAA,YAAA,KAAiB,KAAK,CAAE,CAAA,UAAA,CAAW,KAAM,CAAA,GAAG,CAAC,CAAA;AAAA,IAC/C,OAAO,WAAY,CAAA,KAAA,IAAS,EAAI,EAAA,CAAA,CAAE,cAAc,EAAE,CAAA;AAAA,IAClD,QAAQ,OAAQ,CAAA,KAAA,IAAS,EAAI,EAAA,CAAA,CAAE,cAAc,EAAE,CAAA;AAAA,IAC/C,MAAQ,EAAA,EAAA;AAAA,GACV,CAAE,IACJ,EAAC,CAAA;AACP;;;;"}
@@ -0,0 +1,25 @@
1
+ import React from 'react';
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';
6
+
7
+ const DateSelector = ({
8
+ label,
9
+ initalDate,
10
+ onDateChange
11
+ }) => {
12
+ return /* @__PURE__ */ React.createElement(FormControl, { variant: "standard" }, /* @__PURE__ */ React.createElement(LocalizationProvider, { dateAdapter: AdapterLuxon }, /* @__PURE__ */ React.createElement(
13
+ DesktopDatePicker,
14
+ {
15
+ format: "yyyy-MM-dd",
16
+ label,
17
+ value: initalDate,
18
+ defaultValue: initalDate,
19
+ onChange: onDateChange
20
+ }
21
+ )));
22
+ };
23
+
24
+ export { DateSelector };
25
+ //# sourceMappingURL=DateSelector.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DateSelector.esm.js","sources":["../../../src/components/DateSelector/DateSelector.tsx"],"sourcesContent":["import React from 'react';\nimport { 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":";;;;;;AAaO,MAAM,eAAe,CAAC;AAAA,EAC3B,KAAA;AAAA,EACA,UAAA;AAAA,EACA,YAAA;AACF,CAAyB,KAAA;AACvB,EAAA,2CACG,WAAY,EAAA,EAAA,OAAA,EAAQ,8BAClB,KAAA,CAAA,aAAA,CAAA,oBAAA,EAAA,EAAqB,aAAa,YACjC,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,iBAAA;AAAA,IAAA;AAAA,MACC,MAAO,EAAA,YAAA;AAAA,MACP,KAAA;AAAA,MACA,KAAO,EAAA,UAAA;AAAA,MACP,YAAc,EAAA,UAAA;AAAA,MACd,QAAU,EAAA,YAAA;AAAA,KAAA;AAAA,GAEd,CACF,CAAA,CAAA;AAEJ;;;;"}
@@ -0,0 +1,33 @@
1
+ import React from 'react';
2
+ import Box from '@mui/material/Box';
3
+ import Button from '@mui/material/Button';
4
+
5
+ const SignInContent = ({ handleAuthClick }) => {
6
+ return /* @__PURE__ */ React.createElement(Box, { position: "relative", height: "100%", width: "100%" }, /* @__PURE__ */ React.createElement(
7
+ Box,
8
+ {
9
+ height: "100%",
10
+ width: "80%",
11
+ display: "flex",
12
+ justifyContent: "center",
13
+ alignItems: "center",
14
+ position: "absolute",
15
+ p: 10,
16
+ left: 0,
17
+ top: 0
18
+ },
19
+ /* @__PURE__ */ React.createElement(
20
+ Button,
21
+ {
22
+ variant: "contained",
23
+ color: "primary",
24
+ onClick: handleAuthClick,
25
+ size: "large"
26
+ },
27
+ "Sign in"
28
+ )
29
+ ));
30
+ };
31
+
32
+ export { SignInContent };
33
+ //# sourceMappingURL=SignInContent.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SignInContent.esm.js","sources":["../../../src/components/SignInContent/SignInContent.tsx"],"sourcesContent":["import React from 'react';\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\n\ntype Props = {\n handleAuthClick: React.MouseEventHandler<HTMLElement>;\n};\n\nexport const SignInContent = ({ handleAuthClick }: Props) => {\n return (\n <Box position=\"relative\" height=\"100%\" width=\"100%\">\n <Box\n height=\"100%\"\n width=\"80%\"\n display=\"flex\"\n justifyContent=\"center\"\n alignItems=\"center\"\n position=\"absolute\"\n p={10}\n left={0}\n top={0}\n >\n <Button\n variant=\"contained\"\n color=\"primary\"\n onClick={handleAuthClick}\n size=\"large\"\n >\n Sign in\n </Button>\n </Box>\n </Box>\n );\n};\n"],"names":[],"mappings":";;;;AAQO,MAAM,aAAgB,GAAA,CAAC,EAAE,eAAA,EAA6B,KAAA;AAC3D,EAAA,2CACG,GAAI,EAAA,EAAA,QAAA,EAAS,YAAW,MAAO,EAAA,MAAA,EAAO,OAAM,MAC3C,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,GAAA;AAAA,IAAA;AAAA,MACC,MAAO,EAAA,MAAA;AAAA,MACP,KAAM,EAAA,KAAA;AAAA,MACN,OAAQ,EAAA,MAAA;AAAA,MACR,cAAe,EAAA,QAAA;AAAA,MACf,UAAW,EAAA,QAAA;AAAA,MACX,QAAS,EAAA,UAAA;AAAA,MACT,CAAG,EAAA,EAAA;AAAA,MACH,IAAM,EAAA,CAAA;AAAA,MACN,GAAK,EAAA,CAAA;AAAA,KAAA;AAAA,oBAEL,KAAA,CAAA,aAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,OAAQ,EAAA,WAAA;AAAA,QACR,KAAM,EAAA,SAAA;AAAA,QACN,OAAS,EAAA,eAAA;AAAA,QACT,IAAK,EAAA,OAAA;AAAA,OAAA;AAAA,MACN,SAAA;AAAA,KAED;AAAA,GAEJ,CAAA,CAAA;AAEJ;;;;"}
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
3
+ import { CalendarCard } from './CalendarCard/CalendarCard.esm.js';
4
+
5
+ const queryClient = new QueryClient();
6
+ const VacationCalendar = () => {
7
+ return /* @__PURE__ */ React.createElement(QueryClientProvider, { client: queryClient }, /* @__PURE__ */ React.createElement(CalendarCard, null));
8
+ };
9
+
10
+ export { VacationCalendar };
11
+ //# sourceMappingURL=VacationCalendar.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VacationCalendar.esm.js","sources":["../../src/components/VacationCalendar.tsx"],"sourcesContent":["import React from 'react';\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport { CalendarCard } from './CalendarCard';\n\nconst queryClient = new QueryClient();\n\nexport const VacationCalendar = () => {\n return (\n <QueryClientProvider client={queryClient}>\n <CalendarCard />\n </QueryClientProvider>\n );\n};\n"],"names":[],"mappings":";;;;AAIA,MAAM,WAAA,GAAc,IAAI,WAAY,EAAA,CAAA;AAE7B,MAAM,mBAAmB,MAAM;AACpC,EAAA,2CACG,mBAAoB,EAAA,EAAA,MAAA,EAAQ,WAC3B,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,kBAAa,CAChB,CAAA,CAAA;AAEJ;;;;"}
@@ -0,0 +1,4 @@
1
+ export { VacationCalendar } from './VacationCalendar.esm.js';
2
+ export { vacationCalendarApiRef } from '../api/VacationCalendarApi.esm.js';
3
+ export { VacationCalendarApiClient } from '../api/VacationCalendarClient.esm.js';
4
+ //# sourceMappingURL=index.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
@@ -0,0 +1,63 @@
1
+ import { useInfiniteQuery } from '@tanstack/react-query';
2
+ import { useApi } from '@backstage/core-plugin-api';
3
+ import { slice } from 'lodash';
4
+ import { vacationCalendarApiRef } from '../api/VacationCalendarApi.esm.js';
5
+ import '@backstage/errors';
6
+
7
+ const PAGE_SIZE = 20;
8
+ const useAvailability = (users, startDate, endDate, isSignedIn) => {
9
+ const calendarApi = useApi(vacationCalendarApiRef);
10
+ const {
11
+ data: availablity,
12
+ error,
13
+ isLoading: isAvailabilityLoading,
14
+ isFetching: isAvailabilityFetching,
15
+ hasNextPage,
16
+ fetchNextPage
17
+ } = useInfiniteQuery({
18
+ queryFn: ({ pageParam = 0 }) => {
19
+ const currentUsers = slice(users || [], pageParam, pageParam + PAGE_SIZE);
20
+ return calendarApi.getAvailability(
21
+ {
22
+ users: currentUsers?.map((u) => u.spec.profile?.email ?? "") || [],
23
+ startDateTime: startDate.toISO(),
24
+ endDateTime: endDate.toISO()
25
+ },
26
+ {
27
+ Prefer: 'outlook.timezone="Europe/Stockholm"'
28
+ }
29
+ );
30
+ },
31
+ queryKey: [
32
+ "calendarAvailability",
33
+ users,
34
+ startDate.toISO(),
35
+ endDate.toISO()
36
+ ],
37
+ getNextPageParam: (_, allPages) => {
38
+ const numberOfUsers = allPages.flatMap((p) => p).length;
39
+ if (numberOfUsers === users?.length) {
40
+ return void 0;
41
+ }
42
+ return numberOfUsers;
43
+ },
44
+ cacheTime: 3e4 * 1e3,
45
+ enabled: isSignedIn && startDate.isValid && endDate.isValid && !!users,
46
+ retry: false,
47
+ refetchInterval: 3e4 * 1e3,
48
+ refetchIntervalInBackground: false,
49
+ refetchOnWindowFocus: false,
50
+ refetchOnReconnect: false
51
+ });
52
+ return {
53
+ availablity,
54
+ error,
55
+ isLoading: isAvailabilityLoading,
56
+ isFetching: isAvailabilityFetching,
57
+ hasNextPage,
58
+ fetchNextPage
59
+ };
60
+ };
61
+
62
+ export { useAvailability };
63
+ //# sourceMappingURL=useAvailibility.esm.js.map
@@ -0,0 +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,SAAY,GAAA,EAAA,CAAA;AAEX,MAAM,eAAkB,GAAA,CAC7B,KACA,EAAA,SAAA,EACA,SACA,UACG,KAAA;AACH,EAAM,MAAA,WAAA,GAAc,OAAO,sBAAsB,CAAA,CAAA;AACjD,EAAM,MAAA;AAAA,IACJ,IAAM,EAAA,WAAA;AAAA,IACN,KAAA;AAAA,IACA,SAAW,EAAA,qBAAA;AAAA,IACX,UAAY,EAAA,sBAAA;AAAA,IACZ,WAAA;AAAA,IACA,aAAA;AAAA,MACE,gBAAiB,CAAA;AAAA,IACnB,OAAS,EAAA,CAAC,EAAE,SAAA,GAAY,GAAQ,KAAA;AAC9B,MAAA,MAAM,eAAe,KAAM,CAAA,KAAA,IAAS,EAAI,EAAA,SAAA,EAAW,YAAY,SAAS,CAAA,CAAA;AAExE,MAAA,OAAO,WAAY,CAAA,eAAA;AAAA,QACjB;AAAA,UACE,KAAA,EAAO,YAAc,EAAA,GAAA,CAAI,CAAK,CAAA,KAAA,CAAA,CAAE,KAAK,OAAS,EAAA,KAAA,IAAS,EAAE,CAAA,IAAK,EAAC;AAAA,UAC/D,aAAA,EAAe,UAAU,KAAM,EAAA;AAAA,UAC/B,WAAA,EAAa,QAAQ,KAAM,EAAA;AAAA,SAC7B;AAAA,QACA;AAAA,UACE,MAAQ,EAAA,qCAAA;AAAA,SACV;AAAA,OACF,CAAA;AAAA,KACF;AAAA,IACA,QAAU,EAAA;AAAA,MACR,sBAAA;AAAA,MACA,KAAA;AAAA,MACA,UAAU,KAAM,EAAA;AAAA,MAChB,QAAQ,KAAM,EAAA;AAAA,KAChB;AAAA,IACA,gBAAA,EAAkB,CAAC,CAAA,EAAG,QAAa,KAAA;AACjC,MAAA,MAAM,aAAgB,GAAA,QAAA,CAAS,OAAQ,CAAA,CAAA,CAAA,KAAK,CAAC,CAAE,CAAA,MAAA,CAAA;AAC/C,MAAI,IAAA,aAAA,KAAkB,OAAO,MAAQ,EAAA;AACnC,QAAO,OAAA,KAAA,CAAA,CAAA;AAAA,OACT;AAEA,MAAO,OAAA,aAAA,CAAA;AAAA,KACT;AAAA,IACA,WAAW,GAAQ,GAAA,GAAA;AAAA,IACnB,SAAS,UAAc,IAAA,SAAA,CAAU,WAAW,OAAQ,CAAA,OAAA,IAAW,CAAC,CAAC,KAAA;AAAA,IACjE,KAAO,EAAA,KAAA;AAAA,IACP,iBAAiB,GAAQ,GAAA,GAAA;AAAA,IACzB,2BAA6B,EAAA,KAAA;AAAA,IAC7B,oBAAsB,EAAA,KAAA;AAAA,IACtB,kBAAoB,EAAA,KAAA;AAAA,GACrB,CAAA,CAAA;AACD,EAAO,OAAA;AAAA,IACL,WAAA;AAAA,IACA,KAAA;AAAA,IACA,SAAW,EAAA,qBAAA;AAAA,IACX,UAAY,EAAA,sBAAA;AAAA,IACZ,WAAA;AAAA,IACA,aAAA;AAAA,GACF,CAAA;AACF;;;;"}
@@ -0,0 +1,23 @@
1
+ import { useState, useCallback } from 'react';
2
+ import { useApi, microsoftAuthApiRef } from '@backstage/core-plugin-api';
3
+
4
+ const useSignIn = () => {
5
+ const [isSignedIn, setSignedIn] = useState(false);
6
+ const [isInitialized, setInitialized] = useState(false);
7
+ const authApi = useApi(microsoftAuthApiRef);
8
+ const signIn = useCallback(
9
+ async (optional = false) => {
10
+ const token = await authApi.getAccessToken("Calendars.Read", {
11
+ optional,
12
+ instantPopup: !optional
13
+ });
14
+ setSignedIn(!!token);
15
+ setInitialized(true);
16
+ },
17
+ [authApi, setSignedIn]
18
+ );
19
+ return { isSignedIn, isInitialized, signIn };
20
+ };
21
+
22
+ export { useSignIn };
23
+ //# sourceMappingURL=useSignIn.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSignIn.esm.js","sources":["../../src/hooks/useSignIn.ts"],"sourcesContent":["import { useCallback, useState } from 'react';\nimport { microsoftAuthApiRef, useApi } from '@backstage/core-plugin-api';\n\nexport const useSignIn = () => {\n const [isSignedIn, setSignedIn] = useState(false);\n const [isInitialized, setInitialized] = useState(false);\n const authApi = useApi(microsoftAuthApiRef);\n\n const signIn = useCallback(\n async (optional = false) => {\n const token = await authApi.getAccessToken('Calendars.Read', {\n optional,\n instantPopup: !optional,\n });\n\n setSignedIn(!!token);\n setInitialized(true);\n },\n [authApi, setSignedIn],\n );\n\n return { isSignedIn, isInitialized, signIn };\n};\n"],"names":[],"mappings":";;;AAGO,MAAM,YAAY,MAAM;AAC7B,EAAA,MAAM,CAAC,UAAA,EAAY,WAAW,CAAA,GAAI,SAAS,KAAK,CAAA,CAAA;AAChD,EAAA,MAAM,CAAC,aAAA,EAAe,cAAc,CAAA,GAAI,SAAS,KAAK,CAAA,CAAA;AACtD,EAAM,MAAA,OAAA,GAAU,OAAO,mBAAmB,CAAA,CAAA;AAE1C,EAAA,MAAM,MAAS,GAAA,WAAA;AAAA,IACb,OAAO,WAAW,KAAU,KAAA;AAC1B,MAAA,MAAM,KAAQ,GAAA,MAAM,OAAQ,CAAA,cAAA,CAAe,gBAAkB,EAAA;AAAA,QAC3D,QAAA;AAAA,QACA,cAAc,CAAC,QAAA;AAAA,OAChB,CAAA,CAAA;AAED,MAAY,WAAA,CAAA,CAAC,CAAC,KAAK,CAAA,CAAA;AACnB,MAAA,cAAA,CAAe,IAAI,CAAA,CAAA;AAAA,KACrB;AAAA,IACA,CAAC,SAAS,WAAW,CAAA;AAAA,GACvB,CAAA;AAEA,EAAO,OAAA,EAAE,UAAY,EAAA,aAAA,EAAe,MAAO,EAAA,CAAA;AAC7C;;;;"}
@@ -0,0 +1,84 @@
1
+ /// <reference types="react" />
2
+ import * as react from 'react';
3
+ import * as _backstage_core_plugin_api from '@backstage/core-plugin-api';
4
+ import { OAuthApi, FetchApi } from '@backstage/core-plugin-api';
5
+ import { Calendar, ScheduleInformation } from '@microsoft/microsoft-graph-types';
6
+
7
+ /**
8
+ * Plugin that provides the VacationCalendar api
9
+ * @public */
10
+ declare const vacationCalendarPlugin: _backstage_core_plugin_api.BackstagePlugin<{
11
+ root: _backstage_core_plugin_api.RouteRef<undefined>;
12
+ }, {}, {}>;
13
+ /**
14
+ * Routable extension for VacationCalendarPage
15
+ * @public
16
+ */
17
+ declare const VacationCalendarPage: () => react.JSX.Element;
18
+
19
+ /**
20
+ * The apiref for the VacationCalendar plugin.
21
+ *
22
+ * @public
23
+ */
24
+ declare const vacationCalendarApiRef: _backstage_core_plugin_api.ApiRef<VacationCalendarApi>;
25
+ /**
26
+ * The definition for the VacationCalendar api.
27
+ *
28
+ * @public
29
+ */
30
+ interface VacationCalendarApi {
31
+ /**
32
+ * Fetches schedule items for users
33
+ */
34
+ getCalendars(): Promise<Calendar[]>;
35
+ /**
36
+ * Fetches Microsoft calendars
37
+ */
38
+ getAvailability(params: {
39
+ users: string[];
40
+ startDateTime: string;
41
+ endDateTime: string;
42
+ }, headers: {
43
+ [x: string]: any;
44
+ }): Promise<ScheduleInformation[]>;
45
+ }
46
+
47
+ /**
48
+ * The client implementation for the frontend api.
49
+ *
50
+ * @public
51
+ */
52
+ declare class VacationCalendarApiClient {
53
+ private readonly authApi;
54
+ private readonly fetchApi;
55
+ constructor(options: {
56
+ authApi: OAuthApi;
57
+ fetchApi: FetchApi;
58
+ });
59
+ private get;
60
+ private post;
61
+ /**
62
+ * Fetches Microsoft calendars
63
+ *
64
+ * @returns the MicrosoftValendar objects
65
+ */
66
+ getCalendars(): Promise<Calendar[]>;
67
+ /**
68
+ * Fetches schedule items for users
69
+ *
70
+ * @param users - list of users
71
+ * @param startDateTime - string with start date
72
+ * @param endDateTime - string with end date
73
+ * @returns Microsoft ScheduleInformation items
74
+ */
75
+ getAvailability(params: {
76
+ users: string[];
77
+ startDateTime: string;
78
+ endDateTime: string;
79
+ }, headers: {
80
+ [key in string]: any;
81
+ }): Promise<ScheduleInformation[]>;
82
+ }
83
+
84
+ export { type VacationCalendarApi, VacationCalendarApiClient, VacationCalendarPage, vacationCalendarApiRef, vacationCalendarPlugin };
@@ -0,0 +1,4 @@
1
+ export { VacationCalendarPage, vacationCalendarPlugin } from './plugin.esm.js';
2
+ export { vacationCalendarApiRef } from './api/VacationCalendarApi.esm.js';
3
+ export { VacationCalendarApiClient } from './api/VacationCalendarClient.esm.js';
4
+ //# sourceMappingURL=index.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
@@ -0,0 +1,32 @@
1
+ import 'react-calendar-timeline/lib/Timeline.css';
2
+ import { createPlugin, createApiFactory, microsoftAuthApiRef, fetchApiRef, createRoutableExtension } from '@backstage/core-plugin-api';
3
+ import { rootRouteRef } from './routes.esm.js';
4
+ import { vacationCalendarApiRef } from './api/VacationCalendarApi.esm.js';
5
+ import { VacationCalendarApiClient } from './api/VacationCalendarClient.esm.js';
6
+
7
+ const vacationCalendarPlugin = createPlugin({
8
+ id: "vacation-calendar",
9
+ apis: [
10
+ createApiFactory({
11
+ api: vacationCalendarApiRef,
12
+ deps: {
13
+ authApi: microsoftAuthApiRef,
14
+ fetchApi: fetchApiRef
15
+ },
16
+ factory: ({ authApi, fetchApi }) => new VacationCalendarApiClient({ authApi, fetchApi })
17
+ })
18
+ ],
19
+ routes: {
20
+ root: rootRouteRef
21
+ }
22
+ });
23
+ const VacationCalendarPage = vacationCalendarPlugin.provide(
24
+ createRoutableExtension({
25
+ name: "VacationCalendarPage",
26
+ component: () => import('./components/index.esm.js').then((m) => m.VacationCalendar),
27
+ mountPoint: rootRouteRef
28
+ })
29
+ );
30
+
31
+ export { VacationCalendarPage, vacationCalendarPlugin };
32
+ //# sourceMappingURL=plugin.esm.js.map
@@ -0,0 +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,EAAI,EAAA,mBAAA;AAAA,EACJ,IAAM,EAAA;AAAA,IACJ,gBAAiB,CAAA;AAAA,MACf,GAAK,EAAA,sBAAA;AAAA,MACL,IAAM,EAAA;AAAA,QACJ,OAAS,EAAA,mBAAA;AAAA,QACT,QAAU,EAAA,WAAA;AAAA,OACZ;AAAA,MACA,OAAA,EAAS,CAAC,EAAE,OAAS,EAAA,QAAA,EACnB,KAAA,IAAI,yBAA0B,CAAA,EAAE,OAAS,EAAA,QAAA,EAAU,CAAA;AAAA,KACtD,CAAA;AAAA,GACH;AAAA,EACA,MAAQ,EAAA;AAAA,IACN,IAAM,EAAA,YAAA;AAAA,GACR;AACF,CAAC,EAAA;AAMM,MAAM,uBAAuB,sBAAuB,CAAA,OAAA;AAAA,EACzD,uBAAwB,CAAA;AAAA,IACtB,IAAM,EAAA,sBAAA;AAAA,IACN,SAAA,EAAW,MAAM,OAAO,2BAAc,EAAE,IAAK,CAAA,CAAA,CAAA,KAAK,EAAE,gBAAgB,CAAA;AAAA,IACpE,UAAY,EAAA,YAAA;AAAA,GACb,CAAA;AACH;;;;"}
@@ -0,0 +1,8 @@
1
+ import { createRouteRef } from '@backstage/core-plugin-api';
2
+
3
+ const rootRouteRef = createRouteRef({
4
+ id: "vacation-calendar"
5
+ });
6
+
7
+ export { rootRouteRef };
8
+ //# sourceMappingURL=routes.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.esm.js","sources":["../src/routes.ts"],"sourcesContent":["import { createRouteRef } from '@backstage/core-plugin-api';\n\nexport const rootRouteRef = createRouteRef({\n id: 'vacation-calendar',\n});\n"],"names":[],"mappings":";;AAEO,MAAM,eAAe,cAAe,CAAA;AAAA,EACzC,EAAI,EAAA,mBAAA;AACN,CAAC;;;;"}
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@axis-backstage/plugin-vacation-calendar",
3
+ "version": "0.3.0",
4
+ "main": "dist/index.esm.js",
5
+ "types": "dist/index.d.ts",
6
+ "license": "Apache-2.0",
7
+ "publishConfig": {
8
+ "access": "public",
9
+ "main": "dist/index.esm.js",
10
+ "types": "dist/index.d.ts",
11
+ "directory": "_release/package"
12
+ },
13
+ "backstage": {
14
+ "role": "frontend-plugin",
15
+ "pluginId": "vacation-calendar",
16
+ "pluginPackages": [
17
+ "@axis-backstage/plugin-vacation-calendar"
18
+ ]
19
+ },
20
+ "sideEffects": false,
21
+ "scripts": {
22
+ "start": "backstage-cli package start",
23
+ "build": "backstage-cli package build",
24
+ "lint": "backstage-cli package lint",
25
+ "test": "backstage-cli package test",
26
+ "clean": "backstage-cli package clean",
27
+ "prepack": "backstage-cli package prepack",
28
+ "postpack": "backstage-cli package postpack"
29
+ },
30
+ "dependencies": {
31
+ "@backstage/catalog-model": "^1.5.0",
32
+ "@backstage/core-components": "^0.14.8",
33
+ "@backstage/core-plugin-api": "^1.9.3",
34
+ "@backstage/errors": "^1.2.4",
35
+ "@backstage/plugin-catalog-react": "^1.12.1",
36
+ "@backstage/theme": "^0.5.6",
37
+ "@date-io/luxon": "3.0.0",
38
+ "@material-ui/pickers": "^3.3.11",
39
+ "@microsoft/microsoft-graph-types": "^2.40.0",
40
+ "@mui/lab": "^5.0.0-alpha.170",
41
+ "@mui/material": "^5.15.20",
42
+ "@mui/x-date-pickers": "^7.7.0",
43
+ "@tanstack/react-query": "4.29.1",
44
+ "interactjs": "^1.10.27",
45
+ "lodash": "^4.17.21",
46
+ "luxon": "^3.4.4",
47
+ "react-calendar-timeline": "^0.28.0",
48
+ "react-use": "^17.5.0"
49
+ },
50
+ "peerDependencies": {
51
+ "react": "^16.13.1 || ^17.0.0 || ^18.0.0"
52
+ },
53
+ "devDependencies": {
54
+ "@backstage/catalog-client": "^1.6.5",
55
+ "@backstage/cli": "^0.26.10",
56
+ "@backstage/core-app-api": "^1.12.6",
57
+ "@backstage/dev-utils": "^1.0.33",
58
+ "@backstage/test-utils": "^1.5.6",
59
+ "@testing-library/jest-dom": "^5.10.1",
60
+ "@testing-library/react": "^16.0.0",
61
+ "@testing-library/user-event": "^14.5.2",
62
+ "@types/lodash": "^4.17.5",
63
+ "@types/luxon": "^3.4.2",
64
+ "@types/react-calendar-timeline": "^0.28.6"
65
+ },
66
+ "files": [
67
+ "dist"
68
+ ],
69
+ "module": "./dist/index.esm.js",
70
+ "directory": "_release/package"
71
+ }