@axis-backstage/plugin-vacation-calendar 0.9.3 → 0.10.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,17 @@
1
1
  # @axis-backstage/plugin-vacation-calendar
2
2
 
3
+ ## 0.10.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 8ce6673: Updated lodash dependency, updated tests to use msw 2.
8
+
9
+ ## 0.10.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 38477a3: Sort user calendars alphabetically by display name on the frontend, providing a consistent and predictable user experience. Includes comprehensive tests covering sorting, edge cases, and highlight logic.
14
+
3
15
  ## 0.9.3
4
16
 
5
17
  ### Patch Changes
@@ -65,8 +65,8 @@ const CalendarCard = () => {
65
65
  fetchNextPage
66
66
  } = useAvailability(users, startDate, endDate, isSignedIn);
67
67
  const showLoader = isAvailabilityLoading || isAvailabilityFetching || !isInitialized;
68
- const groups = getGroups(availablity, isUserEntity, users);
69
- const scheduleItems = getScheduleItems(availablity);
68
+ const [groups, groupIndexMap] = getGroups(availablity, isUserEntity, users);
69
+ const scheduleItems = getScheduleItems(availablity, groupIndexMap);
70
70
  if (users?.length === 0) {
71
71
  return /* @__PURE__ */ jsx(
72
72
  ErrorPanel,
@@ -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 = 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":";;;;;;;;;;;;;;;;;;;;;AAmCA,MAAM,gBAAA,GAAmB,EAAA;AAEzB,MAAM,kBAAA,GAAqB,CAAC,KAAA,KAAgD;AAC1E,EAAA,uBACE,GAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACC,EAAA,EAAI;AAAA,QACF,OAAA,EAAS,MAAA;AAAA,QACT,UAAA,EAAY,QAAA;AAAA,QACZ,cAAA,EAAgB,QAAA;AAAA,QAChB,MAAA,EAAQ,MAAA;AAAA,QACR,YAAA,EAAc,gBAAA;AAAA,QACd,MAAA,EAAQ,SAAA;AAAA,QACR,QAAA,EAAU,MAAA;AAAA,QACV,UAAA,EAAY,gBAAA;AAAA,QACZ,KAAA,EAAO,CAAC,KAAA,KAAiB,KAAA,CAAM,QAAQ,IAAA,CAAK,OAAA;AAAA,QAC5C,QAAA,EAAU,UAAA;AAAA,QACV,KAAA,EAAO,KAAA,EAAO,eAAA,CAAgB,QAAA,CAAS,UAAA;AAAA,QACvC,IAAA,EAAM,KAAA,EAAO,eAAA,CAAgB,QAAA,CAAS;AAAA,OACxC;AAAA,MACA,OAAA,EAAS,KAAA,EAAO,gBAAA,EAAiB,CAAE,OAAA;AAAA,MAElC,iBAAO,eAAA,CAAgB;AAAA;AAAA,GAC1B;AAEJ,CAAA;AAEO,MAAM,eAAe,MAAM;AAChC,EAAA,MAAM,EAAE,MAAA,EAAO,GAAI,SAAA,EAAU;AAC7B,EAAA,MAAM,UAAA,GAAa,OAAO,aAAa,CAAA;AAEvC,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,IAAI,QAAA,CAAS,QAAA,CAAS,KAAK,CAAA;AACzD,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,QAAA;AAAA,IAC5B,QAAA,CAAS,GAAA,EAAI,CAAE,KAAA,CAAM,KAAK,EAAE,IAAA,CAAK,EAAE,IAAA,EAAM,gBAAA,EAAkB;AAAA,GAC7D;AAEA,EAAA,MAAM,EAAE,UAAA,EAAY,aAAA,EAAe,MAAA,KAAW,SAAA,EAAU;AAExD,EAAA,QAAA,CAAS,YAAY,MAAA,CAAO,IAAI,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AAE3C,EAAA,MAAM,eACJ,MAAA,CAAO,IAAA,CAAK,aAAY,KAAM,MAAA,IAAU,OAAO,QAAA,CAAS,IAAA;AAE1D,EAAA,MAAM,EAAE,KAAA,EAAO,KAAA,EAAM,GAAI,SAAS,YAAY;AAC5C,IAAA,OAAO,eACH,iBAAA,CAAkB,UAAA,EAAY,MAAM,CAAA,GACpC,kBAAA,CAAmB,YAAY,MAAM,CAAA;AAAA,EAC3C,CAAA,EAAG,CAAC,UAAA,EAAY,MAAM,CAAC,CAAA;AAEvB,EAAA,MAAM;AAAA,IACJ,WAAA;AAAA,IACA,KAAA;AAAA,IACA,SAAA,EAAW,qBAAA;AAAA,IACX,UAAA,EAAY,sBAAA;AAAA,IACZ,WAAA;AAAA,IACA;AAAA,GACF,GAAI,eAAA,CAAgB,KAAA,EAAO,SAAA,EAAW,SAAS,UAAU,CAAA;AAEzD,EAAA,MAAM,UAAA,GACJ,qBAAA,IAAyB,sBAAA,IAA0B,CAAC,aAAA;AAEtD,EAAA,MAAM,MAAA,GAAS,SAAA,CAAU,WAAA,EAAa,YAAA,EAAc,KAAK,CAAA;AACzD,EAAA,MAAM,aAAA,GAAgB,iBAAiB,WAAW,CAAA;AAElD,EAAA,IAAI,KAAA,EAAO,WAAW,CAAA,EAAG;AACvB,IAAA,uBACE,GAAA;AAAA,MAAC,UAAA;AAAA,MAAA;AAAA,QACC,KAAA,EAAM,iBAAA;AAAA,QACN,eAAA,EAAe,IAAA;AAAA,QACf,KAAA,EAAO,MAAM,oCAAoC;AAAA;AAAA,KACnD;AAAA,EAEJ;AACA,EAAA,IAAI,iBAAiB,KAAA,EAAO;AAC1B,IAAA,uBACE,GAAA;AAAA,MAAC,UAAA;AAAA,MAAA;AAAA,QACC,KAAA,EAAM,wBAAA;AAAA,QACN,eAAA,EAAe,IAAA;AAAA,QACf;AAAA;AAAA,KACF;AAAA,EAEJ;AAEA,EAAA,4BACG,OAAA,EAAA,EACC,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,aAAA,EAAA,EAAc,OAAM,wBAAA,EACnB,QAAA,kBAAA,GAAA,CAAC,iBAAc,KAAA,EAAM,kCAAA,EACnB,+BAAC,GAAA,EAAA,EACC,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,UAAA,EAAA,EAAW,OAAA,EAAQ,IAAA,EAAK,QAAA,EAAA,cAAA,EAAY,CAAA;AAAA,sBACrC,GAAA,CAAC,cAAW,QAAA,EAAA,kLAAA,EAIZ,CAAA;AAAA,sBACA,GAAA,CAAC,UAAA,EAAA,EAAW,OAAA,EAAQ,IAAA,EAAK,QAAA,EAAA,aAAA,EAAW,CAAA;AAAA,2BACnC,UAAA,EAAA,EAAW,QAAA,EAAA;AAAA,QAAA,kFAAA;AAAA,QAEI,gBAAA;AAAA,QAAiB;AAAA,OAAA,EACjC;AAAA,KAAA,EACF,GACF,CAAA,EACF,CAAA;AAAA,yBAEC,GAAA,EAAA,EACC,QAAA,EAAA;AAAA,sBAAA,IAAA,CAAC,SAAM,SAAA,EAAU,KAAA,EAAM,GAAA,EAAK,CAAA,EAAG,YAAW,QAAA,EACxC,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,GAAA,EAAA,EACC,QAAA,kBAAA,GAAA;AAAA,UAAC,YAAA;AAAA,UAAA;AAAA,YACC,cAAc,CAAA,CAAA,KAAK;AACjB,cAAA,IAAI,aAAa,QAAA,EAAU;AACzB,gBAAA,MAAM,EAAE,MAAK,GAAI,OAAA,CAAQ,KAAK,CAAA,EAAG,MAAM,EAAE,QAAA,EAAS;AAClD,gBAAA,IAAI,IAAA,IAAQ,IAAA,CAAK,GAAA,CAAI,IAAI,IAAI,gBAAA,EAAkB;AAC7C,kBAAA,UAAA,CAAW,CAAA,CAAE,MAAM,KAAK,CAAA,CAAE,KAAK,EAAE,IAAA,EAAM,gBAAA,EAAkB,CAAC,CAAA;AAAA,gBAC5D;AACA,gBAAA,YAAA,CAAa,CAAC,CAAA;AAAA,cAChB;AAAA,YACF,CAAA;AAAA,YACA,UAAA,EAAY,SAAA;AAAA,YACZ,KAAA,EAAM;AAAA;AAAA,SACR,EACF,CAAA;AAAA,4BACC,GAAA,EAAA,EACC,QAAA,kBAAA,GAAA;AAAA,UAAC,YAAA;AAAA,UAAA;AAAA,YACC,cAAc,CAAA,CAAA,KAAK;AACjB,cAAA,IAAI,aAAa,QAAA,EAAU;AACzB,gBAAA,MAAM,EAAE,MAAK,GAAI,SAAA,CAAU,KAAK,CAAA,EAAG,MAAM,EAAE,QAAA,EAAS;AACpD,gBAAA,IAAI,IAAA,IAAQ,IAAA,CAAK,GAAA,CAAI,IAAI,IAAI,gBAAA,EAAkB;AAC7C,kBAAA,YAAA;AAAA,oBACE,CAAA,CAAE,MAAM,KAAK,CAAA,CAAE,MAAM,EAAE,IAAA,EAAM,kBAAkB;AAAA,mBACjD;AAAA,gBACF;AACA,gBAAA,UAAA,CAAW,CAAa,CAAA;AAAA,cAC1B;AAAA,YACF,CAAA;AAAA,YACA,UAAA,EAAY,OAAA;AAAA,YACZ,KAAA,EAAM;AAAA;AAAA,SACR,EACF,CAAA;AAAA,4BACC,GAAA,EAAA,EACC,QAAA,kBAAA,GAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,SAAS,MAAM;AACb,cAAA,aAAA,EAAc;AAAA,YAChB,CAAA;AAAA,YACA,QAAA,EAAU,cAAc,CAAC,WAAA;AAAA,YACzB,OAAA,EAAQ,WAAA;AAAA,YACR,KAAA,EAAM,SAAA;AAAA,YACP,QAAA,EAAA;AAAA;AAAA,SAED,EACF;AAAA,OAAA,EACF,CAAA;AAAA,MAEC,UAAA,wBACE,GAAA,EAAA,EAAI,EAAA,EAAI,GACP,QAAA,kBAAA,GAAA,CAAC,QAAA,EAAA,EAAS,OAAA,EAAQ,OAAA,EAAQ,CAAA,EAC5B,CAAA;AAAA,MAED,CAAC,cAAc,aAAA,oBACd,GAAA,CAAC,OAAI,CAAA,EAAG,CAAA,EAAG,EAAA,EAAI,CAAA,EAAG,SAAA,EAAW,GAAA,EAAK,WAAW,GAAA,EAAK,QAAA,EAAS,QACzD,QAAA,kBAAA,GAAA,CAAC,aAAA,EAAA,EAAc,iBAAiB,MAAM,MAAA,CAAO,KAAK,CAAA,EAAG,CAAA,EACvD,CAAA;AAAA,MAED,CAAC,qBAAA,IAAyB,UAAA,oBACzB,GAAA,CAAC,GAAA,EAAA,EAAI,EAAA,EAAI,CAAA,EAAG,EAAA,EAAI,CAAA,EAAG,SAAA,EAAW,GAAA,EAAK,QAAA,EAAS,MAAA,EAC1C,QAAA,kBAAA,GAAA;AAAA,QAAC,QAAA;AAAA,QAAA;AAAA,UACC,MAAA;AAAA,UACA,YAAA,EAAc,GAAA;AAAA,UACd,aAAA,EAAe,CAAC,EAAE,KAAA,EAAM,KAAM;AAC5B,YAAA,uBACE,GAAA;AAAA,cAAC,IAAA;AAAA,cAAA;AAAA,gBACC,EAAA,EAAI,CAAA,sBAAA,EAAyB,KAAA,CAAM,MAAA,EAAQ,SAAS,IAAI,CAAA,CAAA;AAAA,gBAExD,QAAA,kBAAA,IAAA;AAAA,kBAAC,KAAA;AAAA,kBAAA;AAAA,oBACC,SAAA,EAAU,cAAA;AAAA,oBACV,KAAA,EAAO;AAAA,sBACL,UAAA,EAAY,KAAA,CAAM,SAAA,GACd,qDAAA,GACA,EAAA;AAAA,sBACJ,UAAA,EAAY,MAAA;AAAA,sBACZ,WAAA,EAAa,KAAA;AAAA,sBACb,OAAA,EAAS,MAAA;AAAA,sBACT,UAAA,EAAY,QAAA;AAAA,sBACZ,QAAA,EAAU,QAAA;AAAA,sBACV,aAAA,EAAe,KAAA;AAAA,sBACf,GAAA,EAAK;AAAA,qBACP;AAAA,oBAEA,QAAA,EAAA;AAAA,sCAAA,GAAA,CAAC,KAAA,EAAA,EACC,QAAA,kBAAA,GAAA;AAAA,wBAAC,MAAA;AAAA,wBAAA;AAAA,0BACC,WAAA,EACE,KAAA,CAAM,MAAA,EAAQ,QAAA,CAAS,WAAA;AAAA,0BAEzB,OAAA,EAAS,KAAA,CAAM,MAAA,EAAQ,IAAA,CAAK,OAAA,EAAS,OAAA;AAAA,0BACrC,YAAA,EAAc;AAAA,4BACZ,KAAA,EAAO,EAAA;AAAA,4BACP,MAAA,EAAQ;AAAA;AACV;AAAA,uBACF,EACF,CAAA;AAAA,sCACA,GAAA,CAAC,SACC,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,WAAU,OAAA,EAAS,QAAA,EAAA,KAAA,CAAM,OAAM,CAAA,EACvC;AAAA;AAAA;AAAA;AACF;AAAA,aACF;AAAA,UAEJ,CAAA;AAAA,UACA,KAAA,EAAO,aAAA;AAAA,UACP,mBAAA,EAAqB,KAAA;AAAA,UACrB,gBAAA,EAAkB,UAAU,QAAA,EAAS;AAAA,UACrC,cAAA,EAAgB,QAAQ,QAAA,EAAS;AAAA,UAEjC,QAAA,kBAAA,IAAA;AAAA,YAAC,eAAA;AAAA,YAAA;AAAA,cACC,KAAA,EAAO;AAAA,gBACL,eAAA,EAAiB,aAAA;AAAA,gBACjB,KAAA,EAAO,OAAA;AAAA,gBACP,QAAA,EAAU,QAAA;AAAA,gBACV,GAAA,EAAK;AAAA,eACP;AAAA,cAEA,QAAA,EAAA;AAAA,gCAAA,GAAA,CAAC,aAAA,EAAA,EACE,QAAA,EAAA,CAAC,EAAE,YAAA,EAAa,KAAM;AACrB,kBAAA,uBAAO,GAAA,CAAC,KAAA,EAAA,EAAK,GAAG,YAAA,EAAa,EAAG,CAAA;AAAA,gBAClC,CAAA,EACF,CAAA;AAAA,gCACA,GAAA;AAAA,kBAAC,UAAA;AAAA,kBAAA;AAAA,oBACC,IAAA,EAAK,eAAA;AAAA,oBACL,gBAAA,EAAkB;AAAA;AAAA,iBACpB;AAAA,gCACA,GAAA,CAAC,UAAA,EAAA,EAAW,gBAAA,EAAkB,kBAAA,EAAoB;AAAA;AAAA;AAAA;AACpD;AAAA,OACF,EACF;AAAA,KAAA,EAEJ;AAAA,GAAA,EACF,CAAA;AAEJ;;;;"}
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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"}
@@ -15,13 +15,13 @@ const getUser = (users, userId) => {
15
15
  const user = users.find((u) => u.metadata.name === name);
16
16
  return user;
17
17
  };
18
- const getScheduleItems = (availablity) => {
18
+ const getScheduleItems = (availablity, groupIndexMap) => {
19
19
  return availablity ? availablity?.pages.flatMap((p) => p).flatMap(
20
20
  (a, i) => (
21
21
  // @ts-ignore
22
22
  a.scheduleItems?.filter((scheduleItem) => scheduleItem.status === "oof").map((s) => ({
23
23
  id: Date.now().toString(36) + Math.random().toString(36).slice(2),
24
- group: i,
24
+ group: groupIndexMap?.get(i) ?? i,
25
25
  start_time: DateTime.fromISO(s.start?.dateTime),
26
26
  end_time: DateTime.fromISO(s.end?.dateTime),
27
27
  canMove: false,
@@ -31,14 +31,33 @@ const getScheduleItems = (availablity) => {
31
31
  ).filter(isTimeLineItem) : [];
32
32
  };
33
33
  const getGroups = (availablity, isUserEntity, users) => {
34
- return availablity ? availablity.pages.flatMap((p) => p).map((a, i) => ({
35
- id: i,
36
- // @ts-ignore
37
- highlight: isUserEntity && a.scheduleId && isUserEntity === head(a.scheduleId.split("@")),
38
- title: getFullName(users || [], a.scheduleId || ""),
39
- entity: getUser(users || [], a.scheduleId || ""),
40
- height: 30
41
- })) : [];
34
+ if (!availablity) {
35
+ return [[], /* @__PURE__ */ new Map()];
36
+ }
37
+ const flattenedSchedules = availablity.pages.flatMap((p) => p).map((a, originalIndex) => ({
38
+ originalIndex,
39
+ schedule: a,
40
+ title: getFullName(users || [], a.scheduleId || "")
41
+ }));
42
+ const sortedSchedules = [...flattenedSchedules].sort((a, b) => {
43
+ const titleA = a.title || "";
44
+ const titleB = b.title || "";
45
+ return titleA.localeCompare(titleB);
46
+ });
47
+ const groupIndexMap = new Map(
48
+ sortedSchedules.map((item, newIndex) => [item.originalIndex, newIndex])
49
+ );
50
+ const groups = sortedSchedules.map((item, newIndex) => {
51
+ const isHighlighted = isUserEntity && item.schedule.scheduleId && isUserEntity === head(item.schedule.scheduleId.split("@"));
52
+ return {
53
+ id: newIndex,
54
+ highlight: !!isHighlighted,
55
+ title: item.title || "",
56
+ entity: getUser(users || [], item.schedule.scheduleId || ""),
57
+ height: 30
58
+ };
59
+ });
60
+ return [groups, groupIndexMap];
42
61
  };
43
62
 
44
63
  export { getGroups, getScheduleItems };
@@ -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) => {\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,IAAA,KACkC;AAClC,EAAA,OAAO,IAAA,KAAS,MAAA;AAClB,CAAA;AAEA,MAAM,WAAA,GAAc,CAAC,KAAA,EAAqB,MAAA,KAAmB;AAC3D,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,MAAA,CAAO,KAAA,CAAM,GAAG,CAAC,CAAA;AACnC,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,IAAA,GAAO,IAAA,CAAK,MAAA,CAAO,KAAA,CAAM,GAAG,CAAC,CAAA;AACnC,EAAA,MAAM,OAAO,KAAA,CAAM,IAAA,CAAK,OAAK,CAAA,CAAE,QAAA,CAAS,SAAS,IAAI,CAAA;AAErD,EAAA,OAAO,IAAA;AACT,CAAA;AAEO,MAAM,gBAAA,GAAmB,CAC9B,WAAA,KACG;AACH,EAAA,OAAO,cACH,WAAA,EAAa,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,CAAA;AAAA,QACP,UAAA,EAAY,QAAA,CAAS,OAAA,CAAQ,CAAA,CAAE,OAAO,QAAS,CAAA;AAAA,QAC/C,QAAA,EAAU,QAAA,CAAS,OAAA,CAAQ,CAAA,CAAE,KAAK,QAAS,CAAA;AAAA,QAC3C,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,WAAA,EACA,YAAA,EACA,KAAA,KACG;AACH,EAAA,OAAO,WAAA,GACH,WAAA,CAAY,KAAA,CACT,OAAA,CAAQ,CAAA,CAAA,KAAK,CAAC,CAAA,CACd,GAAA,CAAI,CAAC,CAAA,EAAG,CAAA,MAAO;AAAA,IACd,EAAA,EAAI,CAAA;AAAA;AAAA,IAEJ,SAAA,EACE,YAAA,IACA,CAAA,CAAE,UAAA,IACF,YAAA,KAAiB,KAAK,CAAA,CAAE,UAAA,CAAW,KAAA,CAAM,GAAG,CAAC,CAAA;AAAA,IAC/C,OAAO,WAAA,CAAY,KAAA,IAAS,EAAC,EAAG,CAAA,CAAE,cAAc,EAAE,CAAA;AAAA,IAClD,QAAQ,OAAA,CAAQ,KAAA,IAAS,EAAC,EAAG,CAAA,CAAE,cAAc,EAAE,CAAA;AAAA,IAC/C,MAAA,EAAQ;AAAA,GACV,CAAE,IACJ,EAAC;AACP;;;;"}
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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axis-backstage/plugin-vacation-calendar",
3
- "version": "0.9.3",
3
+ "version": "0.10.1",
4
4
  "exports": {
5
5
  ".": {
6
6
  "import": "./dist/index.esm.js",
@@ -71,7 +71,7 @@
71
71
  "@mui/x-date-pickers": "^7.7.0",
72
72
  "@tanstack/react-query": "4.29.1",
73
73
  "interactjs": "^1.10.27",
74
- "lodash": "^4.17.21",
74
+ "lodash": "^4.18.1",
75
75
  "luxon": "^3.4.4",
76
76
  "moment": "^2.30.1",
77
77
  "prop-types": "^15.8.1",