@backstage/plugin-home 0.9.9-next.1 → 0.9.9

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 (28) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +3 -642
  3. package/dist/alpha/DefaultHomePageLayout.esm.js +16 -3
  4. package/dist/alpha/DefaultHomePageLayout.esm.js.map +1 -1
  5. package/dist/alpha.d.ts +79 -2
  6. package/dist/alpha.esm.js +112 -21
  7. package/dist/alpha.esm.js.map +1 -1
  8. package/dist/components/CustomHomepage/CustomHomepageGrid.esm.js +32 -11
  9. package/dist/components/CustomHomepage/CustomHomepageGrid.esm.js.map +1 -1
  10. package/dist/homePageComponents/HeaderWorldClock/HeaderWorldClock.esm.js +1 -37
  11. package/dist/homePageComponents/HeaderWorldClock/HeaderWorldClock.esm.js.map +1 -1
  12. package/dist/homePageComponents/Toolkit/Content.esm.js +4 -1
  13. package/dist/homePageComponents/Toolkit/Content.esm.js.map +1 -1
  14. package/dist/homePageComponents/VisitedByType/Content.esm.js +20 -6
  15. package/dist/homePageComponents/VisitedByType/Content.esm.js.map +1 -1
  16. package/dist/homePageComponents/VisitedByType/RecentlyVisited.esm.js +3 -3
  17. package/dist/homePageComponents/VisitedByType/TopVisited.esm.js +3 -3
  18. package/dist/homePageComponents/WorldClock/WorldClock.esm.js +55 -0
  19. package/dist/homePageComponents/WorldClock/WorldClock.esm.js.map +1 -0
  20. package/dist/homePageComponents/WorldClock/clocks.esm.js +40 -0
  21. package/dist/homePageComponents/WorldClock/clocks.esm.js.map +1 -0
  22. package/dist/homePageComponents/WorldClock/index.esm.js +6 -0
  23. package/dist/homePageComponents/WorldClock/index.esm.js.map +1 -0
  24. package/dist/index.d.ts +2 -0
  25. package/dist/package.json.esm.js +1 -1
  26. package/dist/translation.esm.js +4 -0
  27. package/dist/translation.esm.js.map +1 -1
  28. package/package.json +17 -17
@@ -1,44 +1,8 @@
1
1
  import { jsx, Fragment } from 'react/jsx-runtime';
2
2
  import { useState, useEffect } from 'react';
3
3
  import { HeaderLabel } from '@backstage/core-components';
4
+ import { getTimes } from '../WorldClock/clocks.esm.js';
4
5
 
5
- const timeFormat = {
6
- hour: "2-digit",
7
- minute: "2-digit"
8
- };
9
- function getTimes(clockConfigs, customTimeFormat) {
10
- const d = /* @__PURE__ */ new Date();
11
- const lang = window.navigator.language;
12
- const clocks = [];
13
- if (!clockConfigs) {
14
- return clocks;
15
- }
16
- for (const clockConfig of clockConfigs) {
17
- let label = clockConfig.label;
18
- const options = {
19
- timeZone: clockConfig.timeZone,
20
- ...customTimeFormat ?? timeFormat
21
- };
22
- try {
23
- (/* @__PURE__ */ new Date()).toLocaleString(lang, options);
24
- } catch (e) {
25
- console.warn(
26
- `The timezone ${options.timeZone} is invalid. Defaulting to GMT`
27
- );
28
- options.timeZone = "GMT";
29
- label = "GMT";
30
- }
31
- const value = d.toLocaleTimeString(lang, options);
32
- const dateTime = d.toLocaleTimeString(lang, {
33
- timeZone: options.timeZone,
34
- hour: "2-digit",
35
- minute: "2-digit",
36
- hour12: false
37
- });
38
- clocks.push({ label, value, dateTime });
39
- }
40
- return clocks;
41
- }
42
6
  const HeaderWorldClock = (props) => {
43
7
  const { clockConfigs, customTimeFormat } = props;
44
8
  const defaultTimes = [];
@@ -1 +1 @@
1
- {"version":3,"file":"HeaderWorldClock.esm.js","sources":["../../../src/homePageComponents/HeaderWorldClock/HeaderWorldClock.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useState, useEffect } from 'react';\nimport { HeaderLabel } from '@backstage/core-components';\n\nconst timeFormat: Intl.DateTimeFormatOptions = {\n hour: '2-digit',\n minute: '2-digit',\n};\n\ntype TimeObj = {\n label: string;\n value: string;\n dateTime: string;\n};\n\n/** @public */\nexport type ClockConfig = {\n label: string;\n timeZone: string;\n};\n\nfunction getTimes(\n clockConfigs: ClockConfig[],\n customTimeFormat?: Intl.DateTimeFormatOptions,\n) {\n const d = new Date();\n const lang = window.navigator.language;\n\n const clocks: TimeObj[] = [];\n\n if (!clockConfigs) {\n return clocks;\n }\n\n for (const clockConfig of clockConfigs) {\n let label = clockConfig.label;\n\n const options: Intl.DateTimeFormatOptions = {\n timeZone: clockConfig.timeZone,\n ...(customTimeFormat ?? timeFormat),\n };\n\n try {\n new Date().toLocaleString(lang, options);\n } catch (e) {\n // eslint-disable-next-line no-console\n console.warn(\n `The timezone ${options.timeZone} is invalid. Defaulting to GMT`,\n );\n options.timeZone = 'GMT';\n label = 'GMT';\n }\n\n const value = d.toLocaleTimeString(lang, options);\n const dateTime = d.toLocaleTimeString(lang, {\n timeZone: options.timeZone,\n hour: '2-digit',\n minute: '2-digit',\n hour12: false,\n });\n clocks.push({ label, value, dateTime });\n }\n\n return clocks;\n}\n\n/**\n * A component to display a configurable list of clocks for various time zones.\n *\n * @example\n * Here's a simple example:\n * ```\n * // This will give you a clock for the time zone that Stockholm is in\n * // you can add more than one but keep in mind space may be limited\n * const clockConfigs: ClockConfig[] = [\n * {\n * label: 'STO',\n * timeZone: 'Europe/Stockholm',\n * },\n * ];\n *\n * // Setting hour12 to false will make all the clocks show in the 24hr format\n * const timeFormat: Intl.DateTimeFormatOptions = {\n * hour: '2-digit',\n * minute: '2-digit',\n * hour12: false,\n * };\n *\n * // Here is the component in use:\n * <HeaderWorldClock\n * clockConfigs={clockConfigs}\n * customTimeFormat={timeFormat}\n * />\n * ```\n *\n * @public\n */\nexport const HeaderWorldClock = (props: {\n clockConfigs: ClockConfig[];\n customTimeFormat?: Intl.DateTimeFormatOptions;\n}) => {\n const { clockConfigs, customTimeFormat } = props;\n\n const defaultTimes: TimeObj[] = [];\n const [clocks, setTimes] = useState(defaultTimes);\n\n useEffect(() => {\n setTimes(getTimes(clockConfigs, customTimeFormat));\n\n const intervalId = setInterval(() => {\n setTimes(getTimes(clockConfigs, customTimeFormat));\n }, 1000);\n\n return () => {\n clearInterval(intervalId);\n };\n }, [clockConfigs, customTimeFormat]);\n\n if (clocks.length !== 0) {\n return (\n <>\n {clocks.map(clock => (\n <HeaderLabel\n key={clock.label}\n label={clock.label}\n value={<time dateTime={clock.dateTime}>{clock.value}</time>}\n />\n ))}\n </>\n );\n }\n return null;\n};\n"],"names":[],"mappings":";;;;AAmBA,MAAM,UAAA,GAAyC;AAAA,EAC7C,IAAA,EAAM,SAAA;AAAA,EACN,MAAA,EAAQ;AACV,CAAA;AAcA,SAAS,QAAA,CACP,cACA,gBAAA,EACA;AACA,EAAA,MAAM,CAAA,uBAAQ,IAAA,EAAK;AACnB,EAAA,MAAM,IAAA,GAAO,OAAO,SAAA,CAAU,QAAA;AAE9B,EAAA,MAAM,SAAoB,EAAC;AAE3B,EAAA,IAAI,CAAC,YAAA,EAAc;AACjB,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,KAAA,MAAW,eAAe,YAAA,EAAc;AACtC,IAAA,IAAI,QAAQ,WAAA,CAAY,KAAA;AAExB,IAAA,MAAM,OAAA,GAAsC;AAAA,MAC1C,UAAU,WAAA,CAAY,QAAA;AAAA,MACtB,GAAI,gBAAA,IAAoB;AAAA,KAC1B;AAEA,IAAA,IAAI;AACF,MAAA,iBAAA,IAAI,IAAA,EAAK,EAAE,cAAA,CAAe,IAAA,EAAM,OAAO,CAAA;AAAA,IACzC,SAAS,CAAA,EAAG;AAEV,MAAA,OAAA,CAAQ,IAAA;AAAA,QACN,CAAA,aAAA,EAAgB,QAAQ,QAAQ,CAAA,8BAAA;AAAA,OAClC;AACA,MAAA,OAAA,CAAQ,QAAA,GAAW,KAAA;AACnB,MAAA,KAAA,GAAQ,KAAA;AAAA,IACV;AAEA,IAAA,MAAM,KAAA,GAAQ,CAAA,CAAE,kBAAA,CAAmB,IAAA,EAAM,OAAO,CAAA;AAChD,IAAA,MAAM,QAAA,GAAW,CAAA,CAAE,kBAAA,CAAmB,IAAA,EAAM;AAAA,MAC1C,UAAU,OAAA,CAAQ,QAAA;AAAA,MAClB,IAAA,EAAM,SAAA;AAAA,MACN,MAAA,EAAQ,SAAA;AAAA,MACR,MAAA,EAAQ;AAAA,KACT,CAAA;AACD,IAAA,MAAA,CAAO,IAAA,CAAK,EAAE,KAAA,EAAO,KAAA,EAAO,UAAU,CAAA;AAAA,EACxC;AAEA,EAAA,OAAO,MAAA;AACT;AAiCO,MAAM,gBAAA,GAAmB,CAAC,KAAA,KAG3B;AACJ,EAAA,MAAM,EAAE,YAAA,EAAc,gBAAA,EAAiB,GAAI,KAAA;AAE3C,EAAA,MAAM,eAA0B,EAAC;AACjC,EAAA,MAAM,CAAC,MAAA,EAAQ,QAAQ,CAAA,GAAI,SAAS,YAAY,CAAA;AAEhD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,QAAA,CAAS,QAAA,CAAS,YAAA,EAAc,gBAAgB,CAAC,CAAA;AAEjD,IAAA,MAAM,UAAA,GAAa,YAAY,MAAM;AACnC,MAAA,QAAA,CAAS,QAAA,CAAS,YAAA,EAAc,gBAAgB,CAAC,CAAA;AAAA,IACnD,GAAG,GAAI,CAAA;AAEP,IAAA,OAAO,MAAM;AACX,MAAA,aAAA,CAAc,UAAU,CAAA;AAAA,IAC1B,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,YAAA,EAAc,gBAAgB,CAAC,CAAA;AAEnC,EAAA,IAAI,MAAA,CAAO,WAAW,CAAA,EAAG;AACvB,IAAA,uBACE,GAAA,CAAA,QAAA,EAAA,EACG,QAAA,EAAA,MAAA,CAAO,GAAA,CAAI,CAAA,KAAA,qBACV,GAAA;AAAA,MAAC,WAAA;AAAA,MAAA;AAAA,QAEC,OAAO,KAAA,CAAM,KAAA;AAAA,QACb,uBAAO,GAAA,CAAC,MAAA,EAAA,EAAK,UAAU,KAAA,CAAM,QAAA,EAAW,gBAAM,KAAA,EAAM;AAAA,OAAA;AAAA,MAF/C,KAAA,CAAM;AAAA,KAId,CAAA,EACH,CAAA;AAAA,EAEJ;AACA,EAAA,OAAO,IAAA;AACT;;;;"}
1
+ {"version":3,"file":"HeaderWorldClock.esm.js","sources":["../../../src/homePageComponents/HeaderWorldClock/HeaderWorldClock.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useState, useEffect } from 'react';\nimport { HeaderLabel } from '@backstage/core-components';\nimport { getTimes, type ClockConfig, type TimeObj } from '../WorldClock/clocks';\n\nexport type { ClockConfig } from '../WorldClock/clocks';\n\n/**\n * A component to display a configurable list of clocks for various time zones.\n *\n * @example\n * Here's a simple example:\n * ```\n * // This will give you a clock for the time zone that Stockholm is in\n * // you can add more than one but keep in mind space may be limited\n * const clockConfigs: ClockConfig[] = [\n * {\n * label: 'STO',\n * timeZone: 'Europe/Stockholm',\n * },\n * ];\n *\n * // Setting hour12 to false will make all the clocks show in the 24hr format\n * const timeFormat: Intl.DateTimeFormatOptions = {\n * hour: '2-digit',\n * minute: '2-digit',\n * hour12: false,\n * };\n *\n * // Here is the component in use:\n * <HeaderWorldClock\n * clockConfigs={clockConfigs}\n * customTimeFormat={timeFormat}\n * />\n * ```\n *\n * @public\n */\nexport const HeaderWorldClock = (props: {\n clockConfigs: ClockConfig[];\n customTimeFormat?: Intl.DateTimeFormatOptions;\n}) => {\n const { clockConfigs, customTimeFormat } = props;\n\n const defaultTimes: TimeObj[] = [];\n const [clocks, setTimes] = useState(defaultTimes);\n\n useEffect(() => {\n setTimes(getTimes(clockConfigs, customTimeFormat));\n\n const intervalId = setInterval(() => {\n setTimes(getTimes(clockConfigs, customTimeFormat));\n }, 1000);\n\n return () => {\n clearInterval(intervalId);\n };\n }, [clockConfigs, customTimeFormat]);\n\n if (clocks.length !== 0) {\n return (\n <>\n {clocks.map(clock => (\n <HeaderLabel\n key={clock.label}\n label={clock.label}\n value={<time dateTime={clock.dateTime}>{clock.value}</time>}\n />\n ))}\n </>\n );\n }\n return null;\n};\n"],"names":[],"mappings":";;;;;AAqDO,MAAM,gBAAA,GAAmB,CAAC,KAAA,KAG3B;AACJ,EAAA,MAAM,EAAE,YAAA,EAAc,gBAAA,EAAiB,GAAI,KAAA;AAE3C,EAAA,MAAM,eAA0B,EAAC;AACjC,EAAA,MAAM,CAAC,MAAA,EAAQ,QAAQ,CAAA,GAAI,SAAS,YAAY,CAAA;AAEhD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,QAAA,CAAS,QAAA,CAAS,YAAA,EAAc,gBAAgB,CAAC,CAAA;AAEjD,IAAA,MAAM,UAAA,GAAa,YAAY,MAAM;AACnC,MAAA,QAAA,CAAS,QAAA,CAAS,YAAA,EAAc,gBAAgB,CAAC,CAAA;AAAA,IACnD,GAAG,GAAI,CAAA;AAEP,IAAA,OAAO,MAAM;AACX,MAAA,aAAA,CAAc,UAAU,CAAA;AAAA,IAC1B,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,YAAA,EAAc,gBAAgB,CAAC,CAAA;AAEnC,EAAA,IAAI,MAAA,CAAO,WAAW,CAAA,EAAG;AACvB,IAAA,uBACE,GAAA,CAAA,QAAA,EAAA,EACG,QAAA,EAAA,MAAA,CAAO,GAAA,CAAI,CAAA,KAAA,qBACV,GAAA;AAAA,MAAC,WAAA;AAAA,MAAA;AAAA,QAEC,OAAO,KAAA,CAAM,KAAA;AAAA,QACb,uBAAO,GAAA,CAAC,MAAA,EAAA,EAAK,UAAU,KAAA,CAAM,QAAA,EAAW,gBAAM,KAAA,EAAM;AAAA,OAAA;AAAA,MAF/C,KAAA,CAAM;AAAA,KAId,CAAA,EACH,CAAA;AAAA,EAEJ;AACA,EAAA,OAAO,IAAA;AACT;;;;"}
@@ -30,7 +30,10 @@ const useStyles = makeStyles((theme) => ({
30
30
  justifyContent: "center",
31
31
  alignItems: "center",
32
32
  boxShadow: theme.shadows[1],
33
- backgroundColor: theme.palette.background.default
33
+ backgroundColor: theme.palette.background.default,
34
+ "& svg": {
35
+ fontSize: "2rem"
36
+ }
34
37
  }
35
38
  }));
36
39
  const Content = (props) => {
@@ -1 +1 @@
1
- {"version":3,"file":"Content.esm.js","sources":["../../../src/homePageComponents/Toolkit/Content.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Link } from '@backstage/core-components';\nimport List from '@material-ui/core/List';\nimport ListItemIcon from '@material-ui/core/ListItemIcon';\nimport ListItemText from '@material-ui/core/ListItemText';\nimport { makeStyles } from '@material-ui/core/styles';\nimport { useToolkit, Tool } from './Context';\n\nconst useStyles = makeStyles(theme => ({\n toolkit: {\n display: 'flex',\n flexWrap: 'wrap',\n textAlign: 'center',\n },\n tool: {\n margin: theme.spacing(0.5, 1),\n },\n label: {\n marginTop: theme.spacing(1),\n width: '72px',\n fontSize: '0.9em',\n lineHeight: '1.25',\n overflowWrap: 'break-word',\n color: theme.palette.text.secondary,\n },\n icon: {\n width: '64px',\n height: '64px',\n borderRadius: '50px',\n justifyContent: 'center',\n alignItems: 'center',\n boxShadow: theme.shadows[1],\n backgroundColor: theme.palette.background.default,\n },\n}));\n\n/**\n * A component to display a list of tools for the user.\n *\n * @public\n */\nexport const Content = (props: ToolkitContentProps) => {\n const classes = useStyles();\n const toolkit = useToolkit();\n const tools = toolkit?.tools ?? props.tools;\n\n return (\n <List className={classes.toolkit}>\n {tools.map((tool: Tool) => (\n <Link key={tool.url} to={tool.url} className={classes.tool}>\n <ListItemIcon className={classes.icon}>{tool.icon}</ListItemIcon>\n <ListItemText\n secondaryTypographyProps={{ className: classes.label }}\n secondary={tool.label}\n />\n </Link>\n ))}\n </List>\n );\n};\n\n/**\n * Props for Toolkit Content component.\n *\n * @public\n */\nexport type ToolkitContentProps = {\n tools: Tool[];\n};\n"],"names":[],"mappings":";;;;;;;;AAuBA,MAAM,SAAA,GAAY,WAAW,CAAA,KAAA,MAAU;AAAA,EACrC,OAAA,EAAS;AAAA,IACP,OAAA,EAAS,MAAA;AAAA,IACT,QAAA,EAAU,MAAA;AAAA,IACV,SAAA,EAAW;AAAA,GACb;AAAA,EACA,IAAA,EAAM;AAAA,IACJ,MAAA,EAAQ,KAAA,CAAM,OAAA,CAAQ,GAAA,EAAK,CAAC;AAAA,GAC9B;AAAA,EACA,KAAA,EAAO;AAAA,IACL,SAAA,EAAW,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA;AAAA,IAC1B,KAAA,EAAO,MAAA;AAAA,IACP,QAAA,EAAU,OAAA;AAAA,IACV,UAAA,EAAY,MAAA;AAAA,IACZ,YAAA,EAAc,YAAA;AAAA,IACd,KAAA,EAAO,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK;AAAA,GAC5B;AAAA,EACA,IAAA,EAAM;AAAA,IACJ,KAAA,EAAO,MAAA;AAAA,IACP,MAAA,EAAQ,MAAA;AAAA,IACR,YAAA,EAAc,MAAA;AAAA,IACd,cAAA,EAAgB,QAAA;AAAA,IAChB,UAAA,EAAY,QAAA;AAAA,IACZ,SAAA,EAAW,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA;AAAA,IAC1B,eAAA,EAAiB,KAAA,CAAM,OAAA,CAAQ,UAAA,CAAW;AAAA;AAE9C,CAAA,CAAE,CAAA;AAOK,MAAM,OAAA,GAAU,CAAC,KAAA,KAA+B;AACrD,EAAA,MAAM,UAAU,SAAA,EAAU;AAC1B,EAAA,MAAM,UAAU,UAAA,EAAW;AAC3B,EAAA,MAAM,KAAA,GAAQ,OAAA,EAAS,KAAA,IAAS,KAAA,CAAM,KAAA;AAEtC,EAAA,2BACG,IAAA,EAAA,EAAK,SAAA,EAAW,OAAA,CAAQ,OAAA,EACtB,gBAAM,GAAA,CAAI,CAAC,IAAA,qBACV,IAAA,CAAC,QAAoB,EAAA,EAAI,IAAA,CAAK,GAAA,EAAK,SAAA,EAAW,QAAQ,IAAA,EACpD,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,YAAA,EAAA,EAAa,SAAA,EAAW,OAAA,CAAQ,IAAA,EAAO,eAAK,IAAA,EAAK,CAAA;AAAA,oBAClD,GAAA;AAAA,MAAC,YAAA;AAAA,MAAA;AAAA,QACC,wBAAA,EAA0B,EAAE,SAAA,EAAW,OAAA,CAAQ,KAAA,EAAM;AAAA,QACrD,WAAW,IAAA,CAAK;AAAA;AAAA;AAClB,GAAA,EAAA,EALS,IAAA,CAAK,GAMhB,CACD,CAAA,EACH,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"Content.esm.js","sources":["../../../src/homePageComponents/Toolkit/Content.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Link } from '@backstage/core-components';\nimport List from '@material-ui/core/List';\nimport ListItemIcon from '@material-ui/core/ListItemIcon';\nimport ListItemText from '@material-ui/core/ListItemText';\nimport { makeStyles } from '@material-ui/core/styles';\nimport { useToolkit, Tool } from './Context';\n\nconst useStyles = makeStyles(theme => ({\n toolkit: {\n display: 'flex',\n flexWrap: 'wrap',\n textAlign: 'center',\n },\n tool: {\n margin: theme.spacing(0.5, 1),\n },\n label: {\n marginTop: theme.spacing(1),\n width: '72px',\n fontSize: '0.9em',\n lineHeight: '1.25',\n overflowWrap: 'break-word',\n color: theme.palette.text.secondary,\n },\n icon: {\n width: '64px',\n height: '64px',\n borderRadius: '50px',\n justifyContent: 'center',\n alignItems: 'center',\n boxShadow: theme.shadows[1],\n backgroundColor: theme.palette.background.default,\n '& svg': {\n fontSize: '2rem',\n },\n },\n}));\n\n/**\n * A component to display a list of tools for the user.\n *\n * @public\n */\nexport const Content = (props: ToolkitContentProps) => {\n const classes = useStyles();\n const toolkit = useToolkit();\n const tools = toolkit?.tools ?? props.tools;\n\n return (\n <List className={classes.toolkit}>\n {tools.map((tool: Tool) => (\n <Link key={tool.url} to={tool.url} className={classes.tool}>\n <ListItemIcon className={classes.icon}>{tool.icon}</ListItemIcon>\n <ListItemText\n secondaryTypographyProps={{ className: classes.label }}\n secondary={tool.label}\n />\n </Link>\n ))}\n </List>\n );\n};\n\n/**\n * Props for Toolkit Content component.\n *\n * @public\n */\nexport type ToolkitContentProps = {\n tools: Tool[];\n};\n"],"names":[],"mappings":";;;;;;;;AAuBA,MAAM,SAAA,GAAY,WAAW,CAAA,KAAA,MAAU;AAAA,EACrC,OAAA,EAAS;AAAA,IACP,OAAA,EAAS,MAAA;AAAA,IACT,QAAA,EAAU,MAAA;AAAA,IACV,SAAA,EAAW;AAAA,GACb;AAAA,EACA,IAAA,EAAM;AAAA,IACJ,MAAA,EAAQ,KAAA,CAAM,OAAA,CAAQ,GAAA,EAAK,CAAC;AAAA,GAC9B;AAAA,EACA,KAAA,EAAO;AAAA,IACL,SAAA,EAAW,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA;AAAA,IAC1B,KAAA,EAAO,MAAA;AAAA,IACP,QAAA,EAAU,OAAA;AAAA,IACV,UAAA,EAAY,MAAA;AAAA,IACZ,YAAA,EAAc,YAAA;AAAA,IACd,KAAA,EAAO,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK;AAAA,GAC5B;AAAA,EACA,IAAA,EAAM;AAAA,IACJ,KAAA,EAAO,MAAA;AAAA,IACP,MAAA,EAAQ,MAAA;AAAA,IACR,YAAA,EAAc,MAAA;AAAA,IACd,cAAA,EAAgB,QAAA;AAAA,IAChB,UAAA,EAAY,QAAA;AAAA,IACZ,SAAA,EAAW,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA;AAAA,IAC1B,eAAA,EAAiB,KAAA,CAAM,OAAA,CAAQ,UAAA,CAAW,OAAA;AAAA,IAC1C,OAAA,EAAS;AAAA,MACP,QAAA,EAAU;AAAA;AACZ;AAEJ,CAAA,CAAE,CAAA;AAOK,MAAM,OAAA,GAAU,CAAC,KAAA,KAA+B;AACrD,EAAA,MAAM,UAAU,SAAA,EAAU;AAC1B,EAAA,MAAM,UAAU,UAAA,EAAW;AAC3B,EAAA,MAAM,KAAA,GAAQ,OAAA,EAAS,KAAA,IAAS,KAAA,CAAM,KAAA;AAEtC,EAAA,2BACG,IAAA,EAAA,EAAK,SAAA,EAAW,OAAA,CAAQ,OAAA,EACtB,gBAAM,GAAA,CAAI,CAAC,IAAA,qBACV,IAAA,CAAC,QAAoB,EAAA,EAAI,IAAA,CAAK,GAAA,EAAK,SAAA,EAAW,QAAQ,IAAA,EACpD,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,YAAA,EAAA,EAAa,SAAA,EAAW,OAAA,CAAQ,IAAA,EAAO,eAAK,IAAA,EAAK,CAAA;AAAA,oBAClD,GAAA;AAAA,MAAC,YAAA;AAAA,MAAA;AAAA,QACC,wBAAA,EAA0B,EAAE,SAAA,EAAW,OAAA,CAAQ,KAAA,EAAM;AAAA,QACrD,WAAW,IAAA,CAAK;AAAA;AAAA;AAClB,GAAA,EAAA,EALS,IAAA,CAAK,GAMhB,CACD,CAAA,EACH,CAAA;AAEJ;;;;"}
@@ -1,12 +1,15 @@
1
- import { jsx } from 'react/jsx-runtime';
1
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
2
2
  import { useEffect } from 'react';
3
3
  import { createFilterByQueryParamFromConfig } from '../../api/config.esm.js';
4
4
  import { VisitedByType } from './VisitedByType.esm.js';
5
5
  import '@backstage/core-app-api';
6
6
  import { visitsApiRef } from '../../api/VisitsApi.esm.js';
7
7
  import { useContext } from './Context.esm.js';
8
- import { useApi, configApiRef } from '@backstage/core-plugin-api';
8
+ import { useApiHolder, useApi, configApiRef } from '@backstage/core-plugin-api';
9
9
  import useAsync from 'react-use/esm/useAsync';
10
+ import Typography from '@material-ui/core/Typography';
11
+ import { useTranslationRef } from '@backstage/frontend-plugin-api';
12
+ import { homeTranslationRef } from '../../translation.esm.js';
10
13
 
11
14
  const Content = ({
12
15
  visits,
@@ -16,6 +19,9 @@ const Content = ({
16
19
  kind
17
20
  }) => {
18
21
  const { setContext, setVisits, setLoading } = useContext();
22
+ const apiHolder = useApiHolder();
23
+ const visitsApi = apiHolder.get(visitsApiRef);
24
+ const { t } = useTranslationRef(homeTranslationRef);
19
25
  useEffect(() => {
20
26
  const context = {};
21
27
  context.kind = kind;
@@ -30,9 +36,11 @@ const Content = ({
30
36
  setContext((state) => ({ ...state, ...context }));
31
37
  }, [setContext, kind, visits, loading, numVisitsOpen, numVisitsTotal]);
32
38
  const config = useApi(configApiRef);
33
- const visitsApi = useApi(visitsApiRef);
34
39
  const { loading: reqLoading } = useAsync(async () => {
35
- if (!visits && !loading && kind === "recent") {
40
+ if (!visitsApi || visits || loading) {
41
+ return void 0;
42
+ }
43
+ if (kind === "recent") {
36
44
  const filterBy = createFilterByQueryParamFromConfig(
37
45
  config.getOptionalConfigArray("home.recentVisits.filterBy") ?? []
38
46
  );
@@ -42,7 +50,7 @@ const Content = ({
42
50
  ...filterBy && { filterBy }
43
51
  }).then(setVisits);
44
52
  }
45
- if (!visits && !loading && kind === "top") {
53
+ if (kind === "top") {
46
54
  const filterBy = createFilterByQueryParamFromConfig(
47
55
  config.getOptionalConfigArray("home.topVisits.filterBy") ?? []
48
56
  );
@@ -53,12 +61,18 @@ const Content = ({
53
61
  }).then(setVisits);
54
62
  }
55
63
  return void 0;
56
- }, [visitsApi, visits, loading, setVisits]);
64
+ }, [visitsApi, visits, loading, setVisits, kind, numVisitsTotal, config]);
57
65
  useEffect(() => {
58
66
  if (!loading) {
59
67
  setLoading(reqLoading);
60
68
  }
61
69
  }, [loading, setLoading, reqLoading]);
70
+ if (!visitsApi && !visits) {
71
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
72
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "textSecondary", children: t("visitList.disabled.title") }),
73
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "textSecondary", children: t("visitList.disabled.description") })
74
+ ] });
75
+ }
62
76
  return /* @__PURE__ */ jsx(VisitedByType, {});
63
77
  };
64
78
 
@@ -1 +1 @@
1
- {"version":3,"file":"Content.esm.js","sources":["../../../src/homePageComponents/VisitedByType/Content.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useEffect } from 'react';\nimport { createFilterByQueryParamFromConfig } from '../../api/config';\nimport { VisitedByType } from './VisitedByType';\nimport { Visit, visitsApiRef } from '../../api';\nimport { ContextValueOnly, useContext } from './Context';\nimport { configApiRef, useApi } from '@backstage/core-plugin-api';\nimport useAsync from 'react-use/esm/useAsync';\n\n/** @public */\nexport type VisitedByTypeKind = 'recent' | 'top';\n\n/** @public */\nexport type VisitedByTypeProps = {\n visits?: Array<Visit>;\n numVisitsOpen?: number;\n numVisitsTotal?: number;\n loading?: boolean;\n kind: VisitedByTypeKind;\n};\n\n/**\n * Display recently visited pages for the homepage\n * @public\n */\nexport const Content = ({\n visits,\n numVisitsOpen,\n numVisitsTotal,\n loading,\n kind,\n}: VisitedByTypeProps) => {\n const { setContext, setVisits, setLoading } = useContext();\n // Allows behavior override from properties\n useEffect(() => {\n const context: Partial<ContextValueOnly> = {};\n context.kind = kind;\n if (visits) {\n context.visits = visits;\n context.loading = false;\n } else if (loading) {\n context.loading = loading;\n }\n if (numVisitsOpen) context.numVisitsOpen = numVisitsOpen;\n if (numVisitsTotal) context.numVisitsTotal = numVisitsTotal;\n setContext(state => ({ ...state, ...context }));\n }, [setContext, kind, visits, loading, numVisitsOpen, numVisitsTotal]);\n\n const config = useApi(configApiRef);\n // Fetches data from visitsApi in case visits and loading are not provided\n const visitsApi = useApi(visitsApiRef);\n const { loading: reqLoading } = useAsync(async () => {\n if (!visits && !loading && kind === 'recent') {\n const filterBy = createFilterByQueryParamFromConfig(\n config.getOptionalConfigArray('home.recentVisits.filterBy') ?? [],\n );\n return await visitsApi\n .list({\n limit: numVisitsTotal ?? 8,\n orderBy: [{ field: 'timestamp', direction: 'desc' }],\n ...(filterBy && { filterBy }),\n })\n .then(setVisits);\n }\n if (!visits && !loading && kind === 'top') {\n const filterBy = createFilterByQueryParamFromConfig(\n config.getOptionalConfigArray('home.topVisits.filterBy') ?? [],\n );\n return await visitsApi\n .list({\n limit: numVisitsTotal ?? 8,\n orderBy: [{ field: 'hits', direction: 'desc' }],\n ...(filterBy && { filterBy }),\n })\n .then(setVisits);\n }\n return undefined;\n }, [visitsApi, visits, loading, setVisits]);\n useEffect(() => {\n if (!loading) {\n setLoading(reqLoading);\n }\n }, [loading, setLoading, reqLoading]);\n\n return <VisitedByType />;\n};\n"],"names":[],"mappings":";;;;;;;;;;AAwCO,MAAM,UAAU,CAAC;AAAA,EACtB,MAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF,CAAA,KAA0B;AACxB,EAAA,MAAM,EAAE,UAAA,EAAY,SAAA,EAAW,UAAA,KAAe,UAAA,EAAW;AAEzD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,UAAqC,EAAC;AAC5C,IAAA,OAAA,CAAQ,IAAA,GAAO,IAAA;AACf,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,OAAA,CAAQ,MAAA,GAAS,MAAA;AACjB,MAAA,OAAA,CAAQ,OAAA,GAAU,KAAA;AAAA,IACpB,WAAW,OAAA,EAAS;AAClB,MAAA,OAAA,CAAQ,OAAA,GAAU,OAAA;AAAA,IACpB;AACA,IAAA,IAAI,aAAA,UAAuB,aAAA,GAAgB,aAAA;AAC3C,IAAA,IAAI,cAAA,UAAwB,cAAA,GAAiB,cAAA;AAC7C,IAAA,UAAA,CAAW,YAAU,EAAE,GAAG,KAAA,EAAO,GAAG,SAAQ,CAAE,CAAA;AAAA,EAChD,CAAA,EAAG,CAAC,UAAA,EAAY,IAAA,EAAM,QAAQ,OAAA,EAAS,aAAA,EAAe,cAAc,CAAC,CAAA;AAErE,EAAA,MAAM,MAAA,GAAS,OAAO,YAAY,CAAA;AAElC,EAAA,MAAM,SAAA,GAAY,OAAO,YAAY,CAAA;AACrC,EAAA,MAAM,EAAE,OAAA,EAAS,UAAA,EAAW,GAAI,SAAS,YAAY;AACnD,IAAA,IAAI,CAAC,MAAA,IAAU,CAAC,OAAA,IAAW,SAAS,QAAA,EAAU;AAC5C,MAAA,MAAM,QAAA,GAAW,kCAAA;AAAA,QACf,MAAA,CAAO,sBAAA,CAAuB,4BAA4B,CAAA,IAAK;AAAC,OAClE;AACA,MAAA,OAAO,MAAM,UACV,IAAA,CAAK;AAAA,QACJ,OAAO,cAAA,IAAkB,CAAA;AAAA,QACzB,SAAS,CAAC,EAAE,OAAO,WAAA,EAAa,SAAA,EAAW,QAAQ,CAAA;AAAA,QACnD,GAAI,QAAA,IAAY,EAAE,QAAA;AAAS,OAC5B,CAAA,CACA,IAAA,CAAK,SAAS,CAAA;AAAA,IACnB;AACA,IAAA,IAAI,CAAC,MAAA,IAAU,CAAC,OAAA,IAAW,SAAS,KAAA,EAAO;AACzC,MAAA,MAAM,QAAA,GAAW,kCAAA;AAAA,QACf,MAAA,CAAO,sBAAA,CAAuB,yBAAyB,CAAA,IAAK;AAAC,OAC/D;AACA,MAAA,OAAO,MAAM,UACV,IAAA,CAAK;AAAA,QACJ,OAAO,cAAA,IAAkB,CAAA;AAAA,QACzB,SAAS,CAAC,EAAE,OAAO,MAAA,EAAQ,SAAA,EAAW,QAAQ,CAAA;AAAA,QAC9C,GAAI,QAAA,IAAY,EAAE,QAAA;AAAS,OAC5B,CAAA,CACA,IAAA,CAAK,SAAS,CAAA;AAAA,IACnB;AACA,IAAA,OAAO,MAAA;AAAA,EACT,GAAG,CAAC,SAAA,EAAW,MAAA,EAAQ,OAAA,EAAS,SAAS,CAAC,CAAA;AAC1C,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,UAAA,CAAW,UAAU,CAAA;AAAA,IACvB;AAAA,EACF,CAAA,EAAG,CAAC,OAAA,EAAS,UAAA,EAAY,UAAU,CAAC,CAAA;AAEpC,EAAA,2BAAQ,aAAA,EAAA,EAAc,CAAA;AACxB;;;;"}
1
+ {"version":3,"file":"Content.esm.js","sources":["../../../src/homePageComponents/VisitedByType/Content.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useEffect } from 'react';\nimport { createFilterByQueryParamFromConfig } from '../../api/config';\nimport { VisitedByType } from './VisitedByType';\nimport { Visit, visitsApiRef } from '../../api';\nimport { ContextValueOnly, useContext } from './Context';\nimport { configApiRef, useApi, useApiHolder } from '@backstage/core-plugin-api';\nimport useAsync from 'react-use/esm/useAsync';\nimport Typography from '@material-ui/core/Typography';\nimport { useTranslationRef } from '@backstage/frontend-plugin-api';\nimport { homeTranslationRef } from '../../translation';\n\n/** @public */\nexport type VisitedByTypeKind = 'recent' | 'top';\n\n/** @public */\nexport type VisitedByTypeProps = {\n visits?: Array<Visit>;\n numVisitsOpen?: number;\n numVisitsTotal?: number;\n loading?: boolean;\n kind: VisitedByTypeKind;\n};\n\n/**\n * Display recently visited pages for the homepage\n * @public\n */\nexport const Content = ({\n visits,\n numVisitsOpen,\n numVisitsTotal,\n loading,\n kind,\n}: VisitedByTypeProps) => {\n const { setContext, setVisits, setLoading } = useContext();\n const apiHolder = useApiHolder();\n const visitsApi = apiHolder.get(visitsApiRef);\n const { t } = useTranslationRef(homeTranslationRef);\n\n // Allows behavior override from properties\n useEffect(() => {\n const context: Partial<ContextValueOnly> = {};\n context.kind = kind;\n if (visits) {\n context.visits = visits;\n context.loading = false;\n } else if (loading) {\n context.loading = loading;\n }\n if (numVisitsOpen) context.numVisitsOpen = numVisitsOpen;\n if (numVisitsTotal) context.numVisitsTotal = numVisitsTotal;\n setContext(state => ({ ...state, ...context }));\n }, [setContext, kind, visits, loading, numVisitsOpen, numVisitsTotal]);\n\n const config = useApi(configApiRef);\n const { loading: reqLoading } = useAsync(async () => {\n if (!visitsApi || visits || loading) {\n return undefined;\n }\n if (kind === 'recent') {\n const filterBy = createFilterByQueryParamFromConfig(\n config.getOptionalConfigArray('home.recentVisits.filterBy') ?? [],\n );\n return await visitsApi\n .list({\n limit: numVisitsTotal ?? 8,\n orderBy: [{ field: 'timestamp', direction: 'desc' }],\n ...(filterBy && { filterBy }),\n })\n .then(setVisits);\n }\n if (kind === 'top') {\n const filterBy = createFilterByQueryParamFromConfig(\n config.getOptionalConfigArray('home.topVisits.filterBy') ?? [],\n );\n return await visitsApi\n .list({\n limit: numVisitsTotal ?? 8,\n orderBy: [{ field: 'hits', direction: 'desc' }],\n ...(filterBy && { filterBy }),\n })\n .then(setVisits);\n }\n return undefined;\n }, [visitsApi, visits, loading, setVisits, kind, numVisitsTotal, config]);\n\n useEffect(() => {\n if (!loading) {\n setLoading(reqLoading);\n }\n }, [loading, setLoading, reqLoading]);\n\n if (!visitsApi && !visits) {\n return (\n <>\n <Typography variant=\"body2\" color=\"textSecondary\">\n {t('visitList.disabled.title')}\n </Typography>\n <Typography variant=\"body2\" color=\"textSecondary\">\n {t('visitList.disabled.description')}\n </Typography>\n </>\n );\n }\n\n return <VisitedByType />;\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;AA2CO,MAAM,UAAU,CAAC;AAAA,EACtB,MAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF,CAAA,KAA0B;AACxB,EAAA,MAAM,EAAE,UAAA,EAAY,SAAA,EAAW,UAAA,KAAe,UAAA,EAAW;AACzD,EAAA,MAAM,YAAY,YAAA,EAAa;AAC/B,EAAA,MAAM,SAAA,GAAY,SAAA,CAAU,GAAA,CAAI,YAAY,CAAA;AAC5C,EAAA,MAAM,EAAE,CAAA,EAAE,GAAI,iBAAA,CAAkB,kBAAkB,CAAA;AAGlD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,UAAqC,EAAC;AAC5C,IAAA,OAAA,CAAQ,IAAA,GAAO,IAAA;AACf,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,OAAA,CAAQ,MAAA,GAAS,MAAA;AACjB,MAAA,OAAA,CAAQ,OAAA,GAAU,KAAA;AAAA,IACpB,WAAW,OAAA,EAAS;AAClB,MAAA,OAAA,CAAQ,OAAA,GAAU,OAAA;AAAA,IACpB;AACA,IAAA,IAAI,aAAA,UAAuB,aAAA,GAAgB,aAAA;AAC3C,IAAA,IAAI,cAAA,UAAwB,cAAA,GAAiB,cAAA;AAC7C,IAAA,UAAA,CAAW,YAAU,EAAE,GAAG,KAAA,EAAO,GAAG,SAAQ,CAAE,CAAA;AAAA,EAChD,CAAA,EAAG,CAAC,UAAA,EAAY,IAAA,EAAM,QAAQ,OAAA,EAAS,aAAA,EAAe,cAAc,CAAC,CAAA;AAErE,EAAA,MAAM,MAAA,GAAS,OAAO,YAAY,CAAA;AAClC,EAAA,MAAM,EAAE,OAAA,EAAS,UAAA,EAAW,GAAI,SAAS,YAAY;AACnD,IAAA,IAAI,CAAC,SAAA,IAAa,MAAA,IAAU,OAAA,EAAS;AACnC,MAAA,OAAO,MAAA;AAAA,IACT;AACA,IAAA,IAAI,SAAS,QAAA,EAAU;AACrB,MAAA,MAAM,QAAA,GAAW,kCAAA;AAAA,QACf,MAAA,CAAO,sBAAA,CAAuB,4BAA4B,CAAA,IAAK;AAAC,OAClE;AACA,MAAA,OAAO,MAAM,UACV,IAAA,CAAK;AAAA,QACJ,OAAO,cAAA,IAAkB,CAAA;AAAA,QACzB,SAAS,CAAC,EAAE,OAAO,WAAA,EAAa,SAAA,EAAW,QAAQ,CAAA;AAAA,QACnD,GAAI,QAAA,IAAY,EAAE,QAAA;AAAS,OAC5B,CAAA,CACA,IAAA,CAAK,SAAS,CAAA;AAAA,IACnB;AACA,IAAA,IAAI,SAAS,KAAA,EAAO;AAClB,MAAA,MAAM,QAAA,GAAW,kCAAA;AAAA,QACf,MAAA,CAAO,sBAAA,CAAuB,yBAAyB,CAAA,IAAK;AAAC,OAC/D;AACA,MAAA,OAAO,MAAM,UACV,IAAA,CAAK;AAAA,QACJ,OAAO,cAAA,IAAkB,CAAA;AAAA,QACzB,SAAS,CAAC,EAAE,OAAO,MAAA,EAAQ,SAAA,EAAW,QAAQ,CAAA;AAAA,QAC9C,GAAI,QAAA,IAAY,EAAE,QAAA;AAAS,OAC5B,CAAA,CACA,IAAA,CAAK,SAAS,CAAA;AAAA,IACnB;AACA,IAAA,OAAO,MAAA;AAAA,EACT,CAAA,EAAG,CAAC,SAAA,EAAW,MAAA,EAAQ,SAAS,SAAA,EAAW,IAAA,EAAM,cAAA,EAAgB,MAAM,CAAC,CAAA;AAExE,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,UAAA,CAAW,UAAU,CAAA;AAAA,IACvB;AAAA,EACF,CAAA,EAAG,CAAC,OAAA,EAAS,UAAA,EAAY,UAAU,CAAC,CAAA;AAEpC,EAAA,IAAI,CAAC,SAAA,IAAa,CAAC,MAAA,EAAQ;AACzB,IAAA,uBACE,IAAA,CAAA,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,cAAW,OAAA,EAAQ,OAAA,EAAQ,OAAM,eAAA,EAC/B,QAAA,EAAA,CAAA,CAAE,0BAA0B,CAAA,EAC/B,CAAA;AAAA,sBACA,GAAA,CAAC,cAAW,OAAA,EAAQ,OAAA,EAAQ,OAAM,eAAA,EAC/B,QAAA,EAAA,CAAA,CAAE,gCAAgC,CAAA,EACrC;AAAA,KAAA,EACF,CAAA;AAAA,EAEJ;AAEA,EAAA,2BAAQ,aAAA,EAAA,EAAc,CAAA;AACxB;;;;"}
@@ -1,9 +1,9 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
- export { Actions } from './Actions.esm.js';
3
- export { ContextProvider } from './Context.esm.js';
2
+ import { Actions } from './Actions.esm.js';
3
+ import { ContextProvider } from './Context.esm.js';
4
4
  import { Content } from './Content.esm.js';
5
5
 
6
6
  const RecentlyVisitedContent = (props) => /* @__PURE__ */ jsx(Content, { ...props, kind: "recent" });
7
7
 
8
- export { RecentlyVisitedContent as Content };
8
+ export { Actions, RecentlyVisitedContent as Content, ContextProvider };
9
9
  //# sourceMappingURL=RecentlyVisited.esm.js.map
@@ -1,9 +1,9 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
- export { Actions } from './Actions.esm.js';
3
- export { ContextProvider } from './Context.esm.js';
2
+ import { Actions } from './Actions.esm.js';
3
+ import { ContextProvider } from './Context.esm.js';
4
4
  import { Content } from './Content.esm.js';
5
5
 
6
6
  const TopVisitedContent = (props) => /* @__PURE__ */ jsx(Content, { ...props, kind: "top" });
7
7
 
8
- export { TopVisitedContent as Content };
8
+ export { Actions, TopVisitedContent as Content, ContextProvider };
9
9
  //# sourceMappingURL=TopVisited.esm.js.map
@@ -0,0 +1,55 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { useState, useEffect } from 'react';
3
+ import Grid from '@material-ui/core/Grid';
4
+ import Typography from '@material-ui/core/Typography';
5
+ import { makeStyles } from '@material-ui/core/styles';
6
+ import { getTimes } from './clocks.esm.js';
7
+
8
+ const useStyles = makeStyles((theme) => ({
9
+ label: {
10
+ fontWeight: theme.typography.fontWeightBold,
11
+ fontSize: theme.typography.fontSize * 1.5,
12
+ marginBottom: theme.spacing(0.5),
13
+ lineHeight: 1
14
+ },
15
+ value: {
16
+ fontSize: theme.typography.fontSize * 1.5,
17
+ lineHeight: 1,
18
+ color: theme.palette.text.secondary
19
+ }
20
+ }));
21
+ const WorldClock = (props) => {
22
+ const { clockConfigs, customTimeFormat } = props;
23
+ const classes = useStyles();
24
+ const [clocks, setClocks] = useState(
25
+ getTimes(clockConfigs ?? [], customTimeFormat)
26
+ );
27
+ useEffect(() => {
28
+ if (!clockConfigs?.length) {
29
+ return void 0;
30
+ }
31
+ setClocks(getTimes(clockConfigs, customTimeFormat));
32
+ const id = setInterval(() => {
33
+ setClocks(getTimes(clockConfigs, customTimeFormat));
34
+ }, 1e3);
35
+ return () => clearInterval(id);
36
+ }, [clockConfigs, customTimeFormat]);
37
+ if (!clockConfigs?.length) {
38
+ return /* @__PURE__ */ jsx(Typography, { color: "textSecondary", children: "No clocks configured. Add clock configurations in your app-config.yaml to display world clocks." });
39
+ }
40
+ return /* @__PURE__ */ jsx(Grid, { container: true, spacing: 4, children: clocks.map((clock) => /* @__PURE__ */ jsxs(
41
+ Grid,
42
+ {
43
+ item: true,
44
+ "aria-label": `${clock.label}: ${clock.value}`,
45
+ children: [
46
+ /* @__PURE__ */ jsx(Typography, { className: classes.label, children: clock.label }),
47
+ /* @__PURE__ */ jsx(Typography, { className: classes.value, children: /* @__PURE__ */ jsx("time", { dateTime: clock.dateTime, children: clock.value }) })
48
+ ]
49
+ },
50
+ clock.label
51
+ )) });
52
+ };
53
+
54
+ export { WorldClock };
55
+ //# sourceMappingURL=WorldClock.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WorldClock.esm.js","sources":["../../../src/homePageComponents/WorldClock/WorldClock.tsx"],"sourcesContent":["/*\n * Copyright 2026 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useState, useEffect } from 'react';\nimport Grid from '@material-ui/core/Grid';\nimport Typography from '@material-ui/core/Typography';\nimport { makeStyles } from '@material-ui/core/styles';\nimport { getTimes, type ClockConfig } from './clocks';\n\nconst useStyles = makeStyles(theme => ({\n label: {\n fontWeight: theme.typography.fontWeightBold,\n fontSize: theme.typography.fontSize * 1.5,\n marginBottom: theme.spacing(0.5),\n lineHeight: 1,\n },\n value: {\n fontSize: theme.typography.fontSize * 1.5,\n lineHeight: 1,\n color: theme.palette.text.secondary,\n },\n}));\n\nexport const WorldClock = (props: {\n clockConfigs?: ClockConfig[];\n customTimeFormat?: Intl.DateTimeFormatOptions;\n}) => {\n const { clockConfigs, customTimeFormat } = props;\n const classes = useStyles();\n const [clocks, setClocks] = useState(\n getTimes(clockConfigs ?? [], customTimeFormat),\n );\n\n useEffect(() => {\n if (!clockConfigs?.length) {\n return undefined;\n }\n setClocks(getTimes(clockConfigs, customTimeFormat));\n const id = setInterval(() => {\n setClocks(getTimes(clockConfigs, customTimeFormat));\n }, 1000);\n return () => clearInterval(id);\n }, [clockConfigs, customTimeFormat]);\n\n if (!clockConfigs?.length) {\n return (\n <Typography color=\"textSecondary\">\n No clocks configured. Add clock configurations in your app-config.yaml\n to display world clocks.\n </Typography>\n );\n }\n\n return (\n <Grid container spacing={4}>\n {clocks.map(clock => (\n <Grid\n item\n key={clock.label}\n aria-label={`${clock.label}: ${clock.value}`}\n >\n <Typography className={classes.label}>{clock.label}</Typography>\n <Typography className={classes.value}>\n <time dateTime={clock.dateTime}>{clock.value}</time>\n </Typography>\n </Grid>\n ))}\n </Grid>\n );\n};\n"],"names":[],"mappings":";;;;;;;AAsBA,MAAM,SAAA,GAAY,WAAW,CAAA,KAAA,MAAU;AAAA,EACrC,KAAA,EAAO;AAAA,IACL,UAAA,EAAY,MAAM,UAAA,CAAW,cAAA;AAAA,IAC7B,QAAA,EAAU,KAAA,CAAM,UAAA,CAAW,QAAA,GAAW,GAAA;AAAA,IACtC,YAAA,EAAc,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA;AAAA,IAC/B,UAAA,EAAY;AAAA,GACd;AAAA,EACA,KAAA,EAAO;AAAA,IACL,QAAA,EAAU,KAAA,CAAM,UAAA,CAAW,QAAA,GAAW,GAAA;AAAA,IACtC,UAAA,EAAY,CAAA;AAAA,IACZ,KAAA,EAAO,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK;AAAA;AAE9B,CAAA,CAAE,CAAA;AAEK,MAAM,UAAA,GAAa,CAAC,KAAA,KAGrB;AACJ,EAAA,MAAM,EAAE,YAAA,EAAc,gBAAA,EAAiB,GAAI,KAAA;AAC3C,EAAA,MAAM,UAAU,SAAA,EAAU;AAC1B,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAI,QAAA;AAAA,IAC1B,QAAA,CAAS,YAAA,IAAgB,EAAC,EAAG,gBAAgB;AAAA,GAC/C;AAEA,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,cAAc,MAAA,EAAQ;AACzB,MAAA,OAAO,MAAA;AAAA,IACT;AACA,IAAA,SAAA,CAAU,QAAA,CAAS,YAAA,EAAc,gBAAgB,CAAC,CAAA;AAClD,IAAA,MAAM,EAAA,GAAK,YAAY,MAAM;AAC3B,MAAA,SAAA,CAAU,QAAA,CAAS,YAAA,EAAc,gBAAgB,CAAC,CAAA;AAAA,IACpD,GAAG,GAAI,CAAA;AACP,IAAA,OAAO,MAAM,cAAc,EAAE,CAAA;AAAA,EAC/B,CAAA,EAAG,CAAC,YAAA,EAAc,gBAAgB,CAAC,CAAA;AAEnC,EAAA,IAAI,CAAC,cAAc,MAAA,EAAQ;AACzB,IAAA,uBACE,GAAA,CAAC,UAAA,EAAA,EAAW,KAAA,EAAM,eAAA,EAAgB,QAAA,EAAA,iGAAA,EAGlC,CAAA;AAAA,EAEJ;AAEA,EAAA,uBACE,GAAA,CAAC,QAAK,SAAA,EAAS,IAAA,EAAC,SAAS,CAAA,EACtB,QAAA,EAAA,MAAA,CAAO,IAAI,CAAA,KAAA,qBACV,IAAA;AAAA,IAAC,IAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAI,IAAA;AAAA,MAEJ,cAAY,CAAA,EAAG,KAAA,CAAM,KAAK,CAAA,EAAA,EAAK,MAAM,KAAK,CAAA,CAAA;AAAA,MAE1C,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,UAAA,EAAA,EAAW,SAAA,EAAW,OAAA,CAAQ,KAAA,EAAQ,gBAAM,KAAA,EAAM,CAAA;AAAA,wBACnD,GAAA,CAAC,UAAA,EAAA,EAAW,SAAA,EAAW,OAAA,CAAQ,KAAA,EAC7B,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,QAAA,EAAU,KAAA,CAAM,QAAA,EAAW,QAAA,EAAA,KAAA,CAAM,KAAA,EAAM,CAAA,EAC/C;AAAA;AAAA,KAAA;AAAA,IANK,KAAA,CAAM;AAAA,GAQd,CAAA,EACH,CAAA;AAEJ;;;;"}
@@ -0,0 +1,40 @@
1
+ const defaultTimeFormat = {
2
+ hour: "2-digit",
3
+ minute: "2-digit"
4
+ };
5
+ function getTimes(clockConfigs, customTimeFormat) {
6
+ const d = /* @__PURE__ */ new Date();
7
+ const lang = window.navigator.language;
8
+ const clocks = [];
9
+ if (!clockConfigs) {
10
+ return clocks;
11
+ }
12
+ for (const clockConfig of clockConfigs) {
13
+ let label = clockConfig.label;
14
+ const options = {
15
+ timeZone: clockConfig.timeZone,
16
+ ...customTimeFormat ?? defaultTimeFormat
17
+ };
18
+ try {
19
+ (/* @__PURE__ */ new Date()).toLocaleString(lang, options);
20
+ } catch (e) {
21
+ console.warn(
22
+ `The timezone ${options.timeZone} is invalid. Defaulting to GMT`
23
+ );
24
+ options.timeZone = "GMT";
25
+ label = "GMT";
26
+ }
27
+ const value = d.toLocaleTimeString(lang, options);
28
+ const dateTime = d.toLocaleTimeString(lang, {
29
+ timeZone: options.timeZone,
30
+ hour: "2-digit",
31
+ minute: "2-digit",
32
+ hour12: false
33
+ });
34
+ clocks.push({ label, value, dateTime });
35
+ }
36
+ return clocks;
37
+ }
38
+
39
+ export { getTimes };
40
+ //# sourceMappingURL=clocks.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clocks.esm.js","sources":["../../../src/homePageComponents/WorldClock/clocks.ts"],"sourcesContent":["/*\n * Copyright 2026 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/** @public */\nexport type ClockConfig = {\n label: string;\n timeZone: string;\n};\n\nexport type TimeObj = {\n label: string;\n value: string;\n dateTime: string;\n};\n\nconst defaultTimeFormat: Intl.DateTimeFormatOptions = {\n hour: '2-digit',\n minute: '2-digit',\n};\n\nexport function getTimes(\n clockConfigs: ClockConfig[],\n customTimeFormat?: Intl.DateTimeFormatOptions,\n): TimeObj[] {\n const d = new Date();\n const lang = window.navigator.language;\n const clocks: TimeObj[] = [];\n\n if (!clockConfigs) {\n return clocks;\n }\n\n for (const clockConfig of clockConfigs) {\n let label = clockConfig.label;\n\n const options: Intl.DateTimeFormatOptions = {\n timeZone: clockConfig.timeZone,\n ...(customTimeFormat ?? defaultTimeFormat),\n };\n\n try {\n new Date().toLocaleString(lang, options);\n } catch (e) {\n // eslint-disable-next-line no-console\n console.warn(\n `The timezone ${options.timeZone} is invalid. Defaulting to GMT`,\n );\n options.timeZone = 'GMT';\n label = 'GMT';\n }\n\n const value = d.toLocaleTimeString(lang, options);\n const dateTime = d.toLocaleTimeString(lang, {\n timeZone: options.timeZone,\n hour: '2-digit',\n minute: '2-digit',\n hour12: false,\n });\n clocks.push({ label, value, dateTime });\n }\n\n return clocks;\n}\n"],"names":[],"mappings":"AA4BA,MAAM,iBAAA,GAAgD;AAAA,EACpD,IAAA,EAAM,SAAA;AAAA,EACN,MAAA,EAAQ;AACV,CAAA;AAEO,SAAS,QAAA,CACd,cACA,gBAAA,EACW;AACX,EAAA,MAAM,CAAA,uBAAQ,IAAA,EAAK;AACnB,EAAA,MAAM,IAAA,GAAO,OAAO,SAAA,CAAU,QAAA;AAC9B,EAAA,MAAM,SAAoB,EAAC;AAE3B,EAAA,IAAI,CAAC,YAAA,EAAc;AACjB,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,KAAA,MAAW,eAAe,YAAA,EAAc;AACtC,IAAA,IAAI,QAAQ,WAAA,CAAY,KAAA;AAExB,IAAA,MAAM,OAAA,GAAsC;AAAA,MAC1C,UAAU,WAAA,CAAY,QAAA;AAAA,MACtB,GAAI,gBAAA,IAAoB;AAAA,KAC1B;AAEA,IAAA,IAAI;AACF,MAAA,iBAAA,IAAI,IAAA,EAAK,EAAE,cAAA,CAAe,IAAA,EAAM,OAAO,CAAA;AAAA,IACzC,SAAS,CAAA,EAAG;AAEV,MAAA,OAAA,CAAQ,IAAA;AAAA,QACN,CAAA,aAAA,EAAgB,QAAQ,QAAQ,CAAA,8BAAA;AAAA,OAClC;AACA,MAAA,OAAA,CAAQ,QAAA,GAAW,KAAA;AACnB,MAAA,KAAA,GAAQ,KAAA;AAAA,IACV;AAEA,IAAA,MAAM,KAAA,GAAQ,CAAA,CAAE,kBAAA,CAAmB,IAAA,EAAM,OAAO,CAAA;AAChD,IAAA,MAAM,QAAA,GAAW,CAAA,CAAE,kBAAA,CAAmB,IAAA,EAAM;AAAA,MAC1C,UAAU,OAAA,CAAQ,QAAA;AAAA,MAClB,IAAA,EAAM,SAAA;AAAA,MACN,MAAA,EAAQ,SAAA;AAAA,MACR,MAAA,EAAQ;AAAA,KACT,CAAA;AACD,IAAA,MAAA,CAAO,IAAA,CAAK,EAAE,KAAA,EAAO,KAAA,EAAO,UAAU,CAAA;AAAA,EACxC;AAEA,EAAA,OAAO,MAAA;AACT;;;;"}
@@ -0,0 +1,6 @@
1
+ import { WorldClock } from './WorldClock.esm.js';
2
+
3
+
4
+
5
+ export { WorldClock };
6
+ //# sourceMappingURL=index.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
package/dist/index.d.ts CHANGED
@@ -646,6 +646,8 @@ declare const homeTranslationRef: _backstage_frontend_plugin_api.TranslationRef<
646
646
  readonly "widgetSettingsOverlay.deleteWidgetTooltip": "Delete widget";
647
647
  readonly "widgetSettingsOverlay.submitButtonTitle": "Submit";
648
648
  readonly "starredEntityListItem.removeFavoriteEntityTitle": "Remove entity from favorites";
649
+ readonly "visitList.disabled.title": "Visit tracking is not enabled.";
650
+ readonly "visitList.disabled.description": "Enable visit tracking in your app-config.yaml to see your most visited and recently visited pages here.";
649
651
  readonly "visitList.empty.title": "There are no visits to show yet.";
650
652
  readonly "visitList.empty.description": "Once you start using Backstage, your visits will appear here as a quick link to carry on where you left off.";
651
653
  readonly "visitList.few.title": "The more pages you visit, the more pages will appear here.";
@@ -1,5 +1,5 @@
1
1
  var name = "@backstage/plugin-home";
2
- var version = "0.9.9-next.1";
2
+ var version = "0.9.9";
3
3
  var description = "A Backstage plugin that helps you build a home page";
4
4
  var backstage = {
5
5
  role: "frontend-plugin",
@@ -38,6 +38,10 @@ const homeTranslationRef = createTranslationRef({
38
38
  },
39
39
  few: {
40
40
  title: "The more pages you visit, the more pages will appear here."
41
+ },
42
+ disabled: {
43
+ title: "Visit tracking is not enabled.",
44
+ description: "Enable visit tracking in your app-config.yaml to see your most visited and recently visited pages here."
41
45
  }
42
46
  },
43
47
  quickStart: {
@@ -1 +1 @@
1
- {"version":3,"file":"translation.esm.js","sources":["../src/translation.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { createTranslationRef } from '@backstage/frontend-plugin-api';\n\n/**\n * Translation reference for the home plugin.\n * Contains localized text strings for home page components and widgets.\n *\n * @public\n */\nexport const homeTranslationRef = createTranslationRef({\n id: 'home',\n messages: {\n addWidgetDialog: {\n title: 'Add new widget to dashboard',\n noAvailableWidgets:\n 'All available widgets have been added to the dashboard.',\n },\n customHomepageButtons: {\n edit: 'Edit',\n restoreDefaults: 'Restore defaults',\n clearAll: 'Clear all',\n addWidget: 'Add widget',\n save: 'Save',\n cancel: 'Cancel',\n },\n customHomepage: {\n noWidgets: \"No widgets added. Start by clicking the 'Add widget' button.\",\n },\n widgetSettingsOverlay: {\n editSettingsTooltip: 'Edit settings',\n /**\n * @deprecated Use `editSettingsTooltip` instead. This was a typo in the original key.\n */\n editSettingsTooptip: 'Edit settings',\n deleteWidgetTooltip: 'Delete widget',\n submitButtonTitle: 'Submit',\n cancelButtonTitle: 'Cancel',\n },\n starredEntityListItem: {\n removeFavoriteEntityTitle: 'Remove entity from favorites',\n },\n visitList: {\n empty: {\n title: 'There are no visits to show yet.',\n description:\n 'Once you start using Backstage, your visits will appear here as a quick link to carry on where you left off.',\n },\n few: {\n title: 'The more pages you visit, the more pages will appear here.',\n },\n },\n quickStart: {\n title: 'Onboarding',\n description: 'Get started with Backstage',\n learnMoreLinkTitle: 'Learn more',\n },\n starredEntities: {\n noStarredEntitiesMessage:\n 'Click the star beside an entity name to add it to this list!',\n },\n visitedByType: {\n action: {\n viewMore: 'View more',\n viewLess: 'View less',\n },\n },\n featuredDocsCard: {\n learnMoreTitle: 'LEARN MORE',\n empty: {\n title: 'No documents to show',\n description:\n 'Create your own document. Check out our Getting Started Information',\n learnMoreLinkTitle: 'DOCS',\n },\n },\n },\n});\n"],"names":[],"mappings":";;AAuBO,MAAM,qBAAqB,oBAAA,CAAqB;AAAA,EACrD,EAAA,EAAI,MAAA;AAAA,EACJ,QAAA,EAAU;AAAA,IACR,eAAA,EAAiB;AAAA,MACf,KAAA,EAAO,6BAAA;AAAA,MACP,kBAAA,EACE;AAAA,KACJ;AAAA,IACA,qBAAA,EAAuB;AAAA,MACrB,IAAA,EAAM,MAAA;AAAA,MACN,eAAA,EAAiB,kBAAA;AAAA,MACjB,QAAA,EAAU,WAAA;AAAA,MACV,SAAA,EAAW,YAAA;AAAA,MACX,IAAA,EAAM,MAAA;AAAA,MACN,MAAA,EAAQ;AAAA,KACV;AAAA,IACA,cAAA,EAAgB;AAAA,MACd,SAAA,EAAW;AAAA,KACb;AAAA,IACA,qBAAA,EAAuB;AAAA,MACrB,mBAAA,EAAqB,eAAA;AAAA;AAAA;AAAA;AAAA,MAIrB,mBAAA,EAAqB,eAAA;AAAA,MACrB,mBAAA,EAAqB,eAAA;AAAA,MACrB,iBAAA,EAAmB,QAAA;AAAA,MACnB,iBAAA,EAAmB;AAAA,KACrB;AAAA,IACA,qBAAA,EAAuB;AAAA,MACrB,yBAAA,EAA2B;AAAA,KAC7B;AAAA,IACA,SAAA,EAAW;AAAA,MACT,KAAA,EAAO;AAAA,QACL,KAAA,EAAO,kCAAA;AAAA,QACP,WAAA,EACE;AAAA,OACJ;AAAA,MACA,GAAA,EAAK;AAAA,QACH,KAAA,EAAO;AAAA;AACT,KACF;AAAA,IACA,UAAA,EAAY;AAAA,MACV,KAAA,EAAO,YAAA;AAAA,MACP,WAAA,EAAa,4BAAA;AAAA,MACb,kBAAA,EAAoB;AAAA,KACtB;AAAA,IACA,eAAA,EAAiB;AAAA,MACf,wBAAA,EACE;AAAA,KACJ;AAAA,IACA,aAAA,EAAe;AAAA,MACb,MAAA,EAAQ;AAAA,QACN,QAAA,EAAU,WAAA;AAAA,QACV,QAAA,EAAU;AAAA;AACZ,KACF;AAAA,IACA,gBAAA,EAAkB;AAAA,MAChB,cAAA,EAAgB,YAAA;AAAA,MAChB,KAAA,EAAO;AAAA,QACL,KAAA,EAAO,sBAAA;AAAA,QACP,WAAA,EACE,qEAAA;AAAA,QACF,kBAAA,EAAoB;AAAA;AACtB;AACF;AAEJ,CAAC;;;;"}
1
+ {"version":3,"file":"translation.esm.js","sources":["../src/translation.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { createTranslationRef } from '@backstage/frontend-plugin-api';\n\n/**\n * Translation reference for the home plugin.\n * Contains localized text strings for home page components and widgets.\n *\n * @public\n */\nexport const homeTranslationRef = createTranslationRef({\n id: 'home',\n messages: {\n addWidgetDialog: {\n title: 'Add new widget to dashboard',\n noAvailableWidgets:\n 'All available widgets have been added to the dashboard.',\n },\n customHomepageButtons: {\n edit: 'Edit',\n restoreDefaults: 'Restore defaults',\n clearAll: 'Clear all',\n addWidget: 'Add widget',\n save: 'Save',\n cancel: 'Cancel',\n },\n customHomepage: {\n noWidgets: \"No widgets added. Start by clicking the 'Add widget' button.\",\n },\n widgetSettingsOverlay: {\n editSettingsTooltip: 'Edit settings',\n /**\n * @deprecated Use `editSettingsTooltip` instead. This was a typo in the original key.\n */\n editSettingsTooptip: 'Edit settings',\n deleteWidgetTooltip: 'Delete widget',\n submitButtonTitle: 'Submit',\n cancelButtonTitle: 'Cancel',\n },\n starredEntityListItem: {\n removeFavoriteEntityTitle: 'Remove entity from favorites',\n },\n visitList: {\n empty: {\n title: 'There are no visits to show yet.',\n description:\n 'Once you start using Backstage, your visits will appear here as a quick link to carry on where you left off.',\n },\n few: {\n title: 'The more pages you visit, the more pages will appear here.',\n },\n disabled: {\n title: 'Visit tracking is not enabled.',\n description:\n 'Enable visit tracking in your app-config.yaml to see your most visited and recently visited pages here.',\n },\n },\n quickStart: {\n title: 'Onboarding',\n description: 'Get started with Backstage',\n learnMoreLinkTitle: 'Learn more',\n },\n starredEntities: {\n noStarredEntitiesMessage:\n 'Click the star beside an entity name to add it to this list!',\n },\n visitedByType: {\n action: {\n viewMore: 'View more',\n viewLess: 'View less',\n },\n },\n featuredDocsCard: {\n learnMoreTitle: 'LEARN MORE',\n empty: {\n title: 'No documents to show',\n description:\n 'Create your own document. Check out our Getting Started Information',\n learnMoreLinkTitle: 'DOCS',\n },\n },\n },\n});\n"],"names":[],"mappings":";;AAuBO,MAAM,qBAAqB,oBAAA,CAAqB;AAAA,EACrD,EAAA,EAAI,MAAA;AAAA,EACJ,QAAA,EAAU;AAAA,IACR,eAAA,EAAiB;AAAA,MACf,KAAA,EAAO,6BAAA;AAAA,MACP,kBAAA,EACE;AAAA,KACJ;AAAA,IACA,qBAAA,EAAuB;AAAA,MACrB,IAAA,EAAM,MAAA;AAAA,MACN,eAAA,EAAiB,kBAAA;AAAA,MACjB,QAAA,EAAU,WAAA;AAAA,MACV,SAAA,EAAW,YAAA;AAAA,MACX,IAAA,EAAM,MAAA;AAAA,MACN,MAAA,EAAQ;AAAA,KACV;AAAA,IACA,cAAA,EAAgB;AAAA,MACd,SAAA,EAAW;AAAA,KACb;AAAA,IACA,qBAAA,EAAuB;AAAA,MACrB,mBAAA,EAAqB,eAAA;AAAA;AAAA;AAAA;AAAA,MAIrB,mBAAA,EAAqB,eAAA;AAAA,MACrB,mBAAA,EAAqB,eAAA;AAAA,MACrB,iBAAA,EAAmB,QAAA;AAAA,MACnB,iBAAA,EAAmB;AAAA,KACrB;AAAA,IACA,qBAAA,EAAuB;AAAA,MACrB,yBAAA,EAA2B;AAAA,KAC7B;AAAA,IACA,SAAA,EAAW;AAAA,MACT,KAAA,EAAO;AAAA,QACL,KAAA,EAAO,kCAAA;AAAA,QACP,WAAA,EACE;AAAA,OACJ;AAAA,MACA,GAAA,EAAK;AAAA,QACH,KAAA,EAAO;AAAA,OACT;AAAA,MACA,QAAA,EAAU;AAAA,QACR,KAAA,EAAO,gCAAA;AAAA,QACP,WAAA,EACE;AAAA;AACJ,KACF;AAAA,IACA,UAAA,EAAY;AAAA,MACV,KAAA,EAAO,YAAA;AAAA,MACP,WAAA,EAAa,4BAAA;AAAA,MACb,kBAAA,EAAoB;AAAA,KACtB;AAAA,IACA,eAAA,EAAiB;AAAA,MACf,wBAAA,EACE;AAAA,KACJ;AAAA,IACA,aAAA,EAAe;AAAA,MACb,MAAA,EAAQ;AAAA,QACN,QAAA,EAAU,WAAA;AAAA,QACV,QAAA,EAAU;AAAA;AACZ,KACF;AAAA,IACA,gBAAA,EAAkB;AAAA,MAChB,cAAA,EAAgB,YAAA;AAAA,MAChB,KAAA,EAAO;AAAA,QACL,KAAA,EAAO,sBAAA;AAAA,QACP,WAAA,EACE,qEAAA;AAAA,QACF,kBAAA,EAAoB;AAAA;AACtB;AACF;AAEJ,CAAC;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-home",
3
- "version": "0.9.9-next.1",
3
+ "version": "0.9.9",
4
4
  "description": "A Backstage plugin that helps you build a home page",
5
5
  "backstage": {
6
6
  "role": "frontend-plugin",
@@ -68,17 +68,17 @@
68
68
  "test": "backstage-cli package test"
69
69
  },
70
70
  "dependencies": {
71
- "@backstage/catalog-client": "1.16.1",
72
- "@backstage/catalog-model": "1.9.0",
73
- "@backstage/config": "1.3.8",
74
- "@backstage/core-app-api": "1.20.4-next.1",
75
- "@backstage/core-compat-api": "0.5.14-next.1",
76
- "@backstage/core-components": "0.18.13-next.2",
77
- "@backstage/core-plugin-api": "1.12.9-next.0",
78
- "@backstage/frontend-plugin-api": "0.18.0-next.0",
79
- "@backstage/plugin-catalog-react": "3.2.1-next.2",
80
- "@backstage/plugin-home-react": "0.1.41-next.1",
81
- "@backstage/theme": "0.7.3",
71
+ "@backstage/catalog-client": "^1.16.1",
72
+ "@backstage/catalog-model": "^1.10.0",
73
+ "@backstage/config": "^1.3.8",
74
+ "@backstage/core-app-api": "^1.20.4",
75
+ "@backstage/core-compat-api": "^0.5.14",
76
+ "@backstage/core-components": "^0.18.13",
77
+ "@backstage/core-plugin-api": "^1.12.9",
78
+ "@backstage/frontend-plugin-api": "^0.18.0",
79
+ "@backstage/plugin-catalog-react": "^3.2.1",
80
+ "@backstage/plugin-home-react": "^0.1.41",
81
+ "@backstage/theme": "^0.7.3",
82
82
  "@material-ui/core": "^4.12.2",
83
83
  "@material-ui/icons": "^4.9.1",
84
84
  "@material-ui/lab": "4.0.0-alpha.61",
@@ -94,11 +94,11 @@
94
94
  "zod": "^3.25.76 || ^4.0.0"
95
95
  },
96
96
  "devDependencies": {
97
- "@backstage/cli": "0.36.5-next.1",
98
- "@backstage/dev-utils": "1.1.26-next.2",
99
- "@backstage/frontend-defaults": "0.5.5-next.1",
100
- "@backstage/plugin-catalog": "2.0.8-next.2",
101
- "@backstage/test-utils": "1.7.21-next.1",
97
+ "@backstage/cli": "^0.36.5",
98
+ "@backstage/dev-utils": "^1.1.26",
99
+ "@backstage/frontend-defaults": "^0.5.5",
100
+ "@backstage/plugin-catalog": "^2.0.8",
101
+ "@backstage/test-utils": "^1.7.21",
102
102
  "@testing-library/dom": "^10.0.0",
103
103
  "@testing-library/jest-dom": "^6.0.0",
104
104
  "@testing-library/react": "^16.0.0",