@backstage-community/plugin-xcmetrics 0.2.54 → 0.2.55

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 (57) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/{esm/index-ztgFKyGT.esm.js → api/XcmetricsClient.esm.js} +4 -50
  3. package/dist/api/XcmetricsClient.esm.js.map +1 -0
  4. package/dist/api/types.esm.js +8 -0
  5. package/dist/api/types.esm.js.map +1 -0
  6. package/dist/components/Accordion/Accordion.esm.js +43 -0
  7. package/dist/components/Accordion/Accordion.esm.js.map +1 -0
  8. package/dist/components/BuildDetails/BuildDetails.esm.js +139 -0
  9. package/dist/components/BuildDetails/BuildDetails.esm.js.map +1 -0
  10. package/dist/components/BuildList/BuildList.esm.js +73 -0
  11. package/dist/components/BuildList/BuildList.esm.js.map +1 -0
  12. package/dist/components/BuildListFilter/BuildListFilter.esm.js +124 -0
  13. package/dist/components/BuildListFilter/BuildListFilter.esm.js.map +1 -0
  14. package/dist/components/BuildTableColumns.esm.js +61 -0
  15. package/dist/components/BuildTableColumns.esm.js.map +1 -0
  16. package/dist/components/BuildTimeline/BuildTimeline.esm.js +67 -0
  17. package/dist/components/BuildTimeline/BuildTimeline.esm.js.map +1 -0
  18. package/dist/components/DataValue/DataValue.esm.js +11 -0
  19. package/dist/components/DataValue/DataValue.esm.js.map +1 -0
  20. package/dist/components/DatePicker/DatePicker.esm.js +59 -0
  21. package/dist/components/DatePicker/DatePicker.esm.js.map +1 -0
  22. package/dist/components/Overview/Overview.esm.js +53 -0
  23. package/dist/components/Overview/Overview.esm.js.map +1 -0
  24. package/dist/components/OverviewTrends/OverviewTrends.esm.js +132 -0
  25. package/dist/components/OverviewTrends/OverviewTrends.esm.js.map +1 -0
  26. package/dist/components/PreformattedText/PreformattedText.esm.js +81 -0
  27. package/dist/components/PreformattedText/PreformattedText.esm.js.map +1 -0
  28. package/dist/components/StatusCell/StatusCell.esm.js +79 -0
  29. package/dist/components/StatusCell/StatusCell.esm.js.map +1 -0
  30. package/dist/components/StatusIcon/StatusIcon.esm.js +12 -0
  31. package/dist/components/StatusIcon/StatusIcon.esm.js.map +1 -0
  32. package/dist/components/StatusMatrix/StatusMatrix.esm.js +68 -0
  33. package/dist/components/StatusMatrix/StatusMatrix.esm.js.map +1 -0
  34. package/dist/components/Trend/Trend.esm.js +20 -0
  35. package/dist/components/Trend/Trend.esm.js.map +1 -0
  36. package/dist/components/XcmetricsLayout/XcmetricsLayout.esm.js +22 -0
  37. package/dist/components/XcmetricsLayout/XcmetricsLayout.esm.js.map +1 -0
  38. package/dist/components/XcmetricsLayout/index.esm.js +2 -0
  39. package/dist/components/XcmetricsLayout/index.esm.js.map +1 -0
  40. package/dist/index.esm.js +1 -4
  41. package/dist/index.esm.js.map +1 -1
  42. package/dist/plugin.esm.js +33 -0
  43. package/dist/plugin.esm.js.map +1 -0
  44. package/dist/routes.esm.js +13 -0
  45. package/dist/routes.esm.js.map +1 -0
  46. package/dist/utils/array.esm.js +12 -0
  47. package/dist/utils/array.esm.js.map +1 -0
  48. package/dist/utils/buildData.esm.js +21 -0
  49. package/dist/utils/buildData.esm.js.map +1 -0
  50. package/dist/utils/classnames.esm.js +5 -0
  51. package/dist/utils/classnames.esm.js.map +1 -0
  52. package/dist/utils/format.esm.js +30 -0
  53. package/dist/utils/format.esm.js.map +1 -0
  54. package/package.json +11 -7
  55. package/dist/esm/index-BCIpC4bX.esm.js +0 -966
  56. package/dist/esm/index-BCIpC4bX.esm.js.map +0 -1
  57. package/dist/esm/index-ztgFKyGT.esm.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BuildTableColumns.esm.js","sources":["../../src/components/BuildTableColumns.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 Chip from '@material-ui/core/Chip';\nimport React from 'react';\nimport { TableColumn } from '@backstage/core-components';\nimport { Build } from '../api';\nimport { formatTime, formatDuration } from '../utils';\nimport { StatusIcon } from './StatusIcon';\n\nconst baseColumns: TableColumn<Build>[] = [\n {\n field: 'buildStatus',\n render: data => <StatusIcon buildStatus={data.buildStatus} />,\n },\n {\n title: 'Project',\n field: 'projectName',\n },\n {\n title: 'Schema',\n field: 'schema',\n },\n {\n title: 'Started',\n field: 'startedAt',\n render: data => formatTime(data.startTimestamp),\n cellStyle: { whiteSpace: 'nowrap' },\n },\n {\n title: 'Duration',\n field: 'duration',\n render: data => formatDuration(data.duration),\n },\n {\n title: 'User',\n field: 'userid',\n },\n];\n\nconst isCi: TableColumn<Build> = {\n field: 'isCI',\n render: data => data.isCi && <Chip label=\"CI\" size=\"small\" />,\n width: '10',\n sorting: false,\n};\n\nexport const overviewColumns: TableColumn<Build>[] = [...baseColumns, isCi];\n\nexport const buildPageColumns: TableColumn<Build>[] = [\n ...baseColumns,\n {\n title: 'Host',\n field: 'machineName',\n },\n {\n title: 'Warnings',\n field: 'warningCount',\n },\n {\n title: 'Category',\n field: 'category',\n render: data => <Chip label={data.category} size=\"small\" />,\n },\n isCi,\n];\n"],"names":[],"mappings":";;;;;AAuBA,MAAM,WAAoC,GAAA;AAAA,EACxC;AAAA,IACE,KAAO,EAAA,aAAA;AAAA,IACP,QAAQ,CAAQ,IAAA,qBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,WAAA,EAAa,KAAK,WAAa,EAAA,CAAA;AAAA,GAC7D;AAAA,EACA;AAAA,IACE,KAAO,EAAA,SAAA;AAAA,IACP,KAAO,EAAA,aAAA;AAAA,GACT;AAAA,EACA;AAAA,IACE,KAAO,EAAA,QAAA;AAAA,IACP,KAAO,EAAA,QAAA;AAAA,GACT;AAAA,EACA;AAAA,IACE,KAAO,EAAA,SAAA;AAAA,IACP,KAAO,EAAA,WAAA;AAAA,IACP,MAAQ,EAAA,CAAA,IAAA,KAAQ,UAAW,CAAA,IAAA,CAAK,cAAc,CAAA;AAAA,IAC9C,SAAA,EAAW,EAAE,UAAA,EAAY,QAAS,EAAA;AAAA,GACpC;AAAA,EACA;AAAA,IACE,KAAO,EAAA,UAAA;AAAA,IACP,KAAO,EAAA,UAAA;AAAA,IACP,MAAQ,EAAA,CAAA,IAAA,KAAQ,cAAe,CAAA,IAAA,CAAK,QAAQ,CAAA;AAAA,GAC9C;AAAA,EACA;AAAA,IACE,KAAO,EAAA,MAAA;AAAA,IACP,KAAO,EAAA,QAAA;AAAA,GACT;AACF,CAAA,CAAA;AAEA,MAAM,IAA2B,GAAA;AAAA,EAC/B,KAAO,EAAA,MAAA;AAAA,EACP,MAAA,EAAQ,UAAQ,IAAK,CAAA,IAAA,wCAAS,IAAK,EAAA,EAAA,KAAA,EAAM,IAAK,EAAA,IAAA,EAAK,OAAQ,EAAA,CAAA;AAAA,EAC3D,KAAO,EAAA,IAAA;AAAA,EACP,OAAS,EAAA,KAAA;AACX,CAAA,CAAA;AAEO,MAAM,eAAwC,GAAA,CAAC,GAAG,WAAA,EAAa,IAAI,EAAA;AAEnE,MAAM,gBAAyC,GAAA;AAAA,EACpD,GAAG,WAAA;AAAA,EACH;AAAA,IACE,KAAO,EAAA,MAAA;AAAA,IACP,KAAO,EAAA,aAAA;AAAA,GACT;AAAA,EACA;AAAA,IACE,KAAO,EAAA,UAAA;AAAA,IACP,KAAO,EAAA,cAAA;AAAA,GACT;AAAA,EACA;AAAA,IACE,KAAO,EAAA,UAAA;AAAA,IACP,KAAO,EAAA,UAAA;AAAA,IACP,MAAA,EAAQ,0BAAS,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,OAAO,IAAK,CAAA,QAAA,EAAU,MAAK,OAAQ,EAAA,CAAA;AAAA,GAC3D;AAAA,EACA,IAAA;AACF;;;;"}
@@ -0,0 +1,67 @@
1
+ import { makeStyles, createStyles, useTheme } from '@material-ui/core/styles';
2
+ import Typography from '@material-ui/core/Typography';
3
+ import React from 'react';
4
+ import { ResponsiveContainer, BarChart, CartesianGrid, XAxis, YAxis, Tooltip, Legend, Bar } from 'recharts';
5
+ import { formatSecondsInterval, formatPercentage } from '../../utils/format.esm.js';
6
+
7
+ const EMPTY_HEIGHT = 100;
8
+ const useStyles = makeStyles(
9
+ (theme) => createStyles({
10
+ toolTip: {
11
+ backgroundColor: theme.palette.background.paper,
12
+ opacity: 0.8,
13
+ padding: 8
14
+ }
15
+ })
16
+ );
17
+ const TargetToolTip = ({ active, payload, label }) => {
18
+ const classes = useStyles();
19
+ if (active && payload && payload.length === 2) {
20
+ const buildTime = payload[0].value[1] - payload[0].value[0];
21
+ const compileTime = payload[1].value[1] - payload[1].value[0];
22
+ return /* @__PURE__ */ React.createElement("div", { className: classes.toolTip }, `${label}: ${formatSecondsInterval(payload[0].value)}`, /* @__PURE__ */ React.createElement("br", null), buildTime > 0 && `Compile time: ${formatPercentage(compileTime / buildTime)}`);
23
+ }
24
+ return null;
25
+ };
26
+ const getTimelineData = (targets) => {
27
+ const min = targets[0].startTimestampMicroseconds;
28
+ return targets.filter((target) => target.fetchedFromCache === false).map((target) => ({
29
+ name: target.name,
30
+ buildTime: [
31
+ target.startTimestampMicroseconds - min,
32
+ target.endTimestampMicroseconds - min
33
+ ],
34
+ compileTime: [
35
+ target.startTimestampMicroseconds - min,
36
+ target.compilationEndTimestampMicroseconds - min
37
+ ]
38
+ }));
39
+ };
40
+ const BuildTimeline = ({
41
+ targets,
42
+ height,
43
+ width
44
+ }) => {
45
+ const theme = useTheme();
46
+ if (!targets.length) return /* @__PURE__ */ React.createElement(Typography, { paragraph: true }, "No Targets");
47
+ const data = getTimelineData(targets);
48
+ return /* @__PURE__ */ React.createElement(
49
+ ResponsiveContainer,
50
+ {
51
+ height,
52
+ width,
53
+ minHeight: EMPTY_HEIGHT + targets.length * 5
54
+ },
55
+ /* @__PURE__ */ React.createElement(BarChart, { layout: "vertical", data, maxBarSize: 10, barGap: 0 }, /* @__PURE__ */ React.createElement(CartesianGrid, { strokeDasharray: "2 2" }), /* @__PURE__ */ React.createElement(XAxis, { type: "number", domain: [0, "dataMax"] }), /* @__PURE__ */ React.createElement(YAxis, { type: "category", dataKey: "name", padding: { top: 0, bottom: 0 } }), /* @__PURE__ */ React.createElement(Tooltip, { content: /* @__PURE__ */ React.createElement(TargetToolTip, null) }), /* @__PURE__ */ React.createElement(Legend, null), /* @__PURE__ */ React.createElement(
56
+ Bar,
57
+ {
58
+ dataKey: "buildTime",
59
+ fill: theme.palette.grey[400],
60
+ minPointSize: 1
61
+ }
62
+ ), /* @__PURE__ */ React.createElement(Bar, { dataKey: "compileTime", fill: theme.palette.primary.main }))
63
+ );
64
+ };
65
+
66
+ export { BuildTimeline };
67
+ //# sourceMappingURL=BuildTimeline.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BuildTimeline.esm.js","sources":["../../../src/components/BuildTimeline/BuildTimeline.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 { createStyles, makeStyles, useTheme } from '@material-ui/core/styles';\nimport Typography from '@material-ui/core/Typography';\nimport React from 'react';\nimport {\n Bar,\n BarChart,\n CartesianGrid,\n Legend,\n ResponsiveContainer,\n Tooltip,\n XAxis,\n YAxis,\n} from 'recharts';\nimport { Target } from '../../api';\nimport { formatSecondsInterval, formatPercentage } from '../../utils';\n\nconst EMPTY_HEIGHT = 100;\n\nconst useStyles = makeStyles(theme =>\n createStyles({\n toolTip: {\n backgroundColor: theme.palette.background.paper,\n opacity: 0.8,\n padding: 8,\n },\n }),\n);\n\nconst TargetToolTip = ({ active, payload, label }: any) => {\n const classes = useStyles();\n\n if (active && payload && payload.length === 2) {\n const buildTime = payload[0].value[1] - payload[0].value[0];\n const compileTime = payload[1].value[1] - payload[1].value[0];\n return (\n <div className={classes.toolTip}>\n {`${label}: ${formatSecondsInterval(payload[0].value)}`}\n <br />\n {buildTime > 0 &&\n `Compile time: ${formatPercentage(compileTime / buildTime)}`}\n </div>\n );\n }\n\n return null;\n};\n\nconst getTimelineData = (targets: Target[]) => {\n const min = targets[0].startTimestampMicroseconds;\n\n return targets\n .filter(target => target.fetchedFromCache === false)\n .map(target => ({\n name: target.name,\n buildTime: [\n target.startTimestampMicroseconds - min,\n target.endTimestampMicroseconds - min,\n ],\n compileTime: [\n target.startTimestampMicroseconds - min,\n target.compilationEndTimestampMicroseconds - min,\n ],\n }));\n};\n\nexport interface BuildTimelineProps {\n targets: Target[];\n height?: number;\n width?: number;\n}\n\nexport const BuildTimeline = ({\n targets,\n height,\n width,\n}: BuildTimelineProps) => {\n const theme = useTheme();\n if (!targets.length) return <Typography paragraph>No Targets</Typography>;\n\n const data = getTimelineData(targets);\n\n return (\n <ResponsiveContainer\n height={height}\n width={width}\n minHeight={EMPTY_HEIGHT + targets.length * 5}\n >\n <BarChart layout=\"vertical\" data={data} maxBarSize={10} barGap={0}>\n <CartesianGrid strokeDasharray=\"2 2\" />\n <XAxis type=\"number\" domain={[0, 'dataMax']} />\n <YAxis type=\"category\" dataKey=\"name\" padding={{ top: 0, bottom: 0 }} />\n <Tooltip content={<TargetToolTip />} />\n <Legend />\n <Bar\n dataKey=\"buildTime\"\n fill={theme.palette.grey[400]}\n minPointSize={1}\n />\n <Bar dataKey=\"compileTime\" fill={theme.palette.primary.main} />\n </BarChart>\n </ResponsiveContainer>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import Grid from '@material-ui/core/Grid';
2
+ import Typography from '@material-ui/core/Typography';
3
+ import React from 'react';
4
+
5
+ const DataValue = ({ field, value }) => {
6
+ return /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(Typography, { variant: "caption" }, field), /* @__PURE__ */ React.createElement(Typography, { variant: "subtitle1" }, value ?? "--"));
7
+ };
8
+ const DataValueGridItem = (props) => /* @__PURE__ */ React.createElement(Grid, { item: true, xs: props.xs ?? 6, md: props.md ?? 6, lg: props.lg ?? 4 }, /* @__PURE__ */ React.createElement(DataValue, { ...props }));
9
+
10
+ export { DataValue, DataValueGridItem };
11
+ //# sourceMappingURL=DataValue.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DataValue.esm.js","sources":["../../../src/components/DataValue/DataValue.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 */\nimport Grid from '@material-ui/core/Grid';\nimport { GridSize } from '@material-ui/core/Grid';\nimport Typography from '@material-ui/core/Typography';\nimport React from 'react';\n\ninterface DataValueProps {\n field: string;\n value?: string | number | null | undefined;\n}\n\nexport const DataValue = ({ field, value }: DataValueProps) => {\n return (\n <div>\n <Typography variant=\"caption\">{field}</Typography>\n <Typography variant=\"subtitle1\">{value ?? '--'}</Typography>\n </div>\n );\n};\n\ninterface GridProps {\n xs?: GridSize;\n md?: GridSize;\n lg?: GridSize;\n}\n\nexport const DataValueGridItem = (props: DataValueProps & GridProps) => (\n <Grid item xs={props.xs ?? 6} md={props.md ?? 6} lg={props.lg ?? 4}>\n <DataValue {...props} />\n </Grid>\n);\n"],"names":[],"mappings":";;;;AAyBO,MAAM,SAAY,GAAA,CAAC,EAAE,KAAA,EAAO,OAA4B,KAAA;AAC7D,EAAA,uBACG,KAAA,CAAA,aAAA,CAAA,KAAA,EAAA,IAAA,kBACE,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,SAAQ,SAAW,EAAA,EAAA,KAAM,CACrC,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,WAAa,EAAA,EAAA,KAAA,IAAS,IAAK,CACjD,CAAA,CAAA;AAEJ,EAAA;AAQa,MAAA,iBAAA,GAAoB,CAAC,KAChC,qBAAA,KAAA,CAAA,aAAA,CAAC,QAAK,IAAI,EAAA,IAAA,EAAC,EAAI,EAAA,KAAA,CAAM,EAAM,IAAA,CAAA,EAAG,IAAI,KAAM,CAAA,EAAA,IAAM,CAAG,EAAA,EAAA,EAAI,KAAM,CAAA,EAAA,IAAM,qBAC9D,KAAA,CAAA,aAAA,CAAA,SAAA,EAAA,EAAW,GAAG,KAAA,EAAO,CACxB;;;;"}
@@ -0,0 +1,59 @@
1
+ import React from 'react';
2
+ import { createStyles } from '@material-ui/core/styles';
3
+ import withStyles from '@material-ui/core/styles/withStyles';
4
+ import InputBase from '@material-ui/core/InputBase/InputBase';
5
+ import makeStyles from '@material-ui/core/styles/makeStyles';
6
+ import Typography from '@material-ui/core/Typography/Typography';
7
+
8
+ const BootstrapInput = withStyles(
9
+ (theme) => createStyles({
10
+ root: {
11
+ margin: theme.spacing(1, 0),
12
+ maxWidth: 300,
13
+ "label + &": {
14
+ marginTop: theme.spacing(3)
15
+ }
16
+ },
17
+ input: {
18
+ borderRadius: 4,
19
+ position: "relative",
20
+ backgroundColor: theme.palette.background.paper,
21
+ border: "1px solid #ced4da",
22
+ fontSize: 16,
23
+ padding: "10px 26px 10px 12px",
24
+ transition: theme.transitions.create(["border-color", "box-shadow"]),
25
+ fontFamily: "Helvetica Neue",
26
+ height: 25,
27
+ "&:focus": {
28
+ background: theme.palette.background.paper,
29
+ borderRadius: 4
30
+ }
31
+ }
32
+ })
33
+ )(InputBase);
34
+ const useStyles = makeStyles({
35
+ root: {
36
+ display: "flex",
37
+ flexDirection: "column"
38
+ }
39
+ });
40
+ const DatePicker = ({
41
+ label,
42
+ onDateChange,
43
+ ...inputProps
44
+ }) => {
45
+ const classes = useStyles();
46
+ return /* @__PURE__ */ React.createElement("div", { className: classes.root }, /* @__PURE__ */ React.createElement(Typography, { variant: "button" }, label), /* @__PURE__ */ React.createElement(
47
+ BootstrapInput,
48
+ {
49
+ inputProps: { "aria-label": label },
50
+ type: "date",
51
+ fullWidth: true,
52
+ onChange: (event) => onDateChange?.(event.target.value),
53
+ ...inputProps
54
+ }
55
+ ));
56
+ };
57
+
58
+ export { DatePicker };
59
+ //# sourceMappingURL=DatePicker.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DatePicker.esm.js","sources":["../../../src/components/DatePicker/DatePicker.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 React from 'react';\nimport { createStyles } from '@material-ui/core/styles';\nimport { InputProps } from '@material-ui/core/Input';\nimport withStyles from '@material-ui/core/styles/withStyles';\nimport { Theme } from '@material-ui/core/styles/createTheme';\nimport InputBase from '@material-ui/core/InputBase/InputBase';\nimport makeStyles from '@material-ui/core/styles/makeStyles';\nimport Typography from '@material-ui/core/Typography/Typography';\n\nconst BootstrapInput = withStyles((theme: Theme) =>\n createStyles({\n root: {\n margin: theme.spacing(1, 0),\n maxWidth: 300,\n 'label + &': {\n marginTop: theme.spacing(3),\n },\n },\n input: {\n borderRadius: 4,\n position: 'relative',\n backgroundColor: theme.palette.background.paper,\n border: '1px solid #ced4da',\n fontSize: 16,\n padding: '10px 26px 10px 12px',\n transition: theme.transitions.create(['border-color', 'box-shadow']),\n fontFamily: 'Helvetica Neue',\n height: 25,\n '&:focus': {\n background: theme.palette.background.paper,\n borderRadius: 4,\n },\n },\n }),\n)(InputBase);\n\nconst useStyles = makeStyles({\n root: {\n display: 'flex',\n flexDirection: 'column',\n },\n});\n\ninterface DatePickerProps {\n label: string;\n onDateChange?: (date: string) => void;\n}\n\nexport const DatePicker = ({\n label,\n onDateChange,\n ...inputProps\n}: InputProps & DatePickerProps) => {\n const classes = useStyles();\n\n return (\n <div className={classes.root}>\n <Typography variant=\"button\">{label}</Typography>\n <BootstrapInput\n inputProps={{ 'aria-label': label }}\n type=\"date\"\n fullWidth\n onChange={event => onDateChange?.(event.target.value)}\n {...inputProps}\n />\n </div>\n );\n};\n"],"names":[],"mappings":";;;;;;;AAyBA,MAAM,cAAiB,GAAA,UAAA;AAAA,EAAW,CAAC,UACjC,YAAa,CAAA;AAAA,IACX,IAAM,EAAA;AAAA,MACJ,MAAQ,EAAA,KAAA,CAAM,OAAQ,CAAA,CAAA,EAAG,CAAC,CAAA;AAAA,MAC1B,QAAU,EAAA,GAAA;AAAA,MACV,WAAa,EAAA;AAAA,QACX,SAAA,EAAW,KAAM,CAAA,OAAA,CAAQ,CAAC,CAAA;AAAA,OAC5B;AAAA,KACF;AAAA,IACA,KAAO,EAAA;AAAA,MACL,YAAc,EAAA,CAAA;AAAA,MACd,QAAU,EAAA,UAAA;AAAA,MACV,eAAA,EAAiB,KAAM,CAAA,OAAA,CAAQ,UAAW,CAAA,KAAA;AAAA,MAC1C,MAAQ,EAAA,mBAAA;AAAA,MACR,QAAU,EAAA,EAAA;AAAA,MACV,OAAS,EAAA,qBAAA;AAAA,MACT,YAAY,KAAM,CAAA,WAAA,CAAY,OAAO,CAAC,cAAA,EAAgB,YAAY,CAAC,CAAA;AAAA,MACnE,UAAY,EAAA,gBAAA;AAAA,MACZ,MAAQ,EAAA,EAAA;AAAA,MACR,SAAW,EAAA;AAAA,QACT,UAAA,EAAY,KAAM,CAAA,OAAA,CAAQ,UAAW,CAAA,KAAA;AAAA,QACrC,YAAc,EAAA,CAAA;AAAA,OAChB;AAAA,KACF;AAAA,GACD,CAAA;AACH,CAAA,CAAE,SAAS,CAAA,CAAA;AAEX,MAAM,YAAY,UAAW,CAAA;AAAA,EAC3B,IAAM,EAAA;AAAA,IACJ,OAAS,EAAA,MAAA;AAAA,IACT,aAAe,EAAA,QAAA;AAAA,GACjB;AACF,CAAC,CAAA,CAAA;AAOM,MAAM,aAAa,CAAC;AAAA,EACzB,KAAA;AAAA,EACA,YAAA;AAAA,EACA,GAAG,UAAA;AACL,CAAoC,KAAA;AAClC,EAAA,MAAM,UAAU,SAAU,EAAA,CAAA;AAE1B,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,KAAI,EAAA,EAAA,SAAA,EAAW,OAAQ,CAAA,IAAA,EAAA,sCACrB,UAAW,EAAA,EAAA,OAAA,EAAQ,QAAU,EAAA,EAAA,KAAM,CACpC,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,cAAA;AAAA,IAAA;AAAA,MACC,UAAA,EAAY,EAAE,YAAA,EAAc,KAAM,EAAA;AAAA,MAClC,IAAK,EAAA,MAAA;AAAA,MACL,SAAS,EAAA,IAAA;AAAA,MACT,QAAU,EAAA,CAAA,KAAA,KAAS,YAAe,GAAA,KAAA,CAAM,OAAO,KAAK,CAAA;AAAA,MACnD,GAAG,UAAA;AAAA,KAAA;AAAA,GAER,CAAA,CAAA;AAEJ;;;;"}
@@ -0,0 +1,53 @@
1
+ import React from 'react';
2
+ import { Progress, EmptyState, ContentHeader, SupportButton, Table, InfoCard } from '@backstage/core-components';
3
+ import { useApi } from '@backstage/core-plugin-api';
4
+ import { xcmetricsApiRef } from '../../api/types.esm.js';
5
+ import '@backstage/errors';
6
+ import 'luxon';
7
+ import useAsync from 'react-use/esm/useAsync';
8
+ import Alert from '@material-ui/lab/Alert';
9
+ import { StatusMatrix } from '../StatusMatrix/StatusMatrix.esm.js';
10
+ import Grid from '@material-ui/core/Grid';
11
+ import { OverviewTrends } from '../OverviewTrends/OverviewTrends.esm.js';
12
+ import { overviewColumns } from '../BuildTableColumns.esm.js';
13
+
14
+ const Overview = () => {
15
+ const client = useApi(xcmetricsApiRef);
16
+ const {
17
+ value: builds,
18
+ loading,
19
+ error
20
+ } = useAsync(async () => client.getBuilds(), []);
21
+ if (loading) {
22
+ return /* @__PURE__ */ React.createElement(Progress, null);
23
+ } else if (error) {
24
+ return /* @__PURE__ */ React.createElement(Alert, { severity: "error" }, error.message);
25
+ }
26
+ if (!builds || !builds.length) {
27
+ return /* @__PURE__ */ React.createElement(
28
+ EmptyState,
29
+ {
30
+ missing: "data",
31
+ title: "No builds to show",
32
+ description: "There are no builds in XCMetrics yet"
33
+ }
34
+ );
35
+ }
36
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(ContentHeader, { title: "XCMetrics Dashboard" }, /* @__PURE__ */ React.createElement(SupportButton, null, "Dashboard for XCMetrics")), /* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 3, direction: "row" }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12, md: 8, lg: 8, xl: 9 }, /* @__PURE__ */ React.createElement(
37
+ Table,
38
+ {
39
+ options: {
40
+ paging: false,
41
+ search: false,
42
+ sorting: false,
43
+ draggable: false
44
+ },
45
+ data: builds,
46
+ columns: overviewColumns,
47
+ title: /* @__PURE__ */ React.createElement(React.Fragment, null, "Latest Builds", /* @__PURE__ */ React.createElement(StatusMatrix, null))
48
+ }
49
+ )), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12, md: 4, lg: 4, xl: 3 }, /* @__PURE__ */ React.createElement(InfoCard, null, /* @__PURE__ */ React.createElement(OverviewTrends, null)))));
50
+ };
51
+
52
+ export { Overview };
53
+ //# sourceMappingURL=Overview.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Overview.esm.js","sources":["../../../src/components/Overview/Overview.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 */\nimport React from 'react';\nimport {\n ContentHeader,\n SupportButton,\n Progress,\n Table,\n EmptyState,\n InfoCard,\n} from '@backstage/core-components';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { xcmetricsApiRef } from '../../api';\nimport useAsync from 'react-use/esm/useAsync';\nimport Alert from '@material-ui/lab/Alert';\nimport { StatusMatrix } from '../StatusMatrix';\nimport Grid from '@material-ui/core/Grid';\nimport { OverviewTrends } from '../OverviewTrends';\nimport { overviewColumns } from '../BuildTableColumns';\n\nexport const Overview = () => {\n const client = useApi(xcmetricsApiRef);\n const {\n value: builds,\n loading,\n error,\n } = useAsync(async () => client.getBuilds(), []);\n\n if (loading) {\n return <Progress />;\n } else if (error) {\n return <Alert severity=\"error\">{error.message}</Alert>;\n }\n\n if (!builds || !builds.length) {\n return (\n <EmptyState\n missing=\"data\"\n title=\"No builds to show\"\n description=\"There are no builds in XCMetrics yet\"\n />\n );\n }\n\n return (\n <>\n <ContentHeader title=\"XCMetrics Dashboard\">\n <SupportButton>Dashboard for XCMetrics</SupportButton>\n </ContentHeader>\n <Grid container spacing={3} direction=\"row\">\n <Grid item xs={12} md={8} lg={8} xl={9}>\n <Table\n options={{\n paging: false,\n search: false,\n sorting: false,\n draggable: false,\n }}\n data={builds}\n columns={overviewColumns}\n title={\n <>\n Latest Builds\n <StatusMatrix />\n </>\n }\n />\n </Grid>\n <Grid item xs={12} md={4} lg={4} xl={3}>\n <InfoCard>\n <OverviewTrends />\n </InfoCard>\n </Grid>\n </Grid>\n </>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;AAiCO,MAAM,WAAW,MAAM;AAC5B,EAAM,MAAA,MAAA,GAAS,OAAO,eAAe,CAAA,CAAA;AACrC,EAAM,MAAA;AAAA,IACJ,KAAO,EAAA,MAAA;AAAA,IACP,OAAA;AAAA,IACA,KAAA;AAAA,MACE,QAAS,CAAA,YAAY,OAAO,SAAU,EAAA,EAAG,EAAE,CAAA,CAAA;AAE/C,EAAA,IAAI,OAAS,EAAA;AACX,IAAA,2CAAQ,QAAS,EAAA,IAAA,CAAA,CAAA;AAAA,aACR,KAAO,EAAA;AAChB,IAAA,uBAAQ,KAAA,CAAA,aAAA,CAAA,KAAA,EAAA,EAAM,QAAS,EAAA,OAAA,EAAA,EAAS,MAAM,OAAQ,CAAA,CAAA;AAAA,GAChD;AAEA,EAAA,IAAI,CAAC,MAAA,IAAU,CAAC,MAAA,CAAO,MAAQ,EAAA;AAC7B,IACE,uBAAA,KAAA,CAAA,aAAA;AAAA,MAAC,UAAA;AAAA,MAAA;AAAA,QACC,OAAQ,EAAA,MAAA;AAAA,QACR,KAAM,EAAA,mBAAA;AAAA,QACN,WAAY,EAAA,sCAAA;AAAA,OAAA;AAAA,KACd,CAAA;AAAA,GAEJ;AAEA,EAAA,uBAEI,KAAA,CAAA,aAAA,CAAA,KAAA,CAAA,QAAA,EAAA,IAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,aAAc,EAAA,EAAA,KAAA,EAAM,qBACnB,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,aAAc,EAAA,IAAA,EAAA,yBAAuB,CACxC,CAAA,kBACC,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,SAAS,EAAA,IAAA,EAAC,OAAS,EAAA,CAAA,EAAG,SAAU,EAAA,KAAA,EAAA,kBACnC,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,IAAI,EAAA,IAAA,EAAC,EAAI,EAAA,EAAA,EAAI,EAAI,EAAA,CAAA,EAAG,EAAI,EAAA,CAAA,EAAG,IAAI,CACnC,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,OAAS,EAAA;AAAA,QACP,MAAQ,EAAA,KAAA;AAAA,QACR,MAAQ,EAAA,KAAA;AAAA,QACR,OAAS,EAAA,KAAA;AAAA,QACT,SAAW,EAAA,KAAA;AAAA,OACb;AAAA,MACA,IAAM,EAAA,MAAA;AAAA,MACN,OAAS,EAAA,eAAA;AAAA,MACT,KACE,kBAAA,KAAA,CAAA,aAAA,CAAA,KAAA,CAAA,QAAA,EAAA,IAAA,EAAE,eAEA,kBAAA,KAAA,CAAA,aAAA,CAAC,kBAAa,CAChB,CAAA;AAAA,KAAA;AAAA,GAGN,mBACC,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,MAAI,IAAC,EAAA,EAAA,EAAI,IAAI,EAAI,EAAA,CAAA,EAAG,IAAI,CAAG,EAAA,EAAA,EAAI,qBAClC,KAAA,CAAA,aAAA,CAAA,QAAA,EAAA,IAAA,sCACE,cAAe,EAAA,IAAA,CAClB,CACF,CACF,CACF,CAAA,CAAA;AAEJ;;;;"}
@@ -0,0 +1,132 @@
1
+ import Grid from '@material-ui/core/Grid';
2
+ import { makeStyles, useTheme } from '@material-ui/core/styles';
3
+ import React, { useState } from 'react';
4
+ import { Progress, Select } from '@backstage/core-components';
5
+ import { Trend } from '../Trend/Trend.esm.js';
6
+ import Alert from '@material-ui/lab/Alert';
7
+ import AlertTitle from '@material-ui/lab/AlertTitle';
8
+ import { xcmetricsApiRef } from '../../api/types.esm.js';
9
+ import '@backstage/errors';
10
+ import 'luxon';
11
+ import useAsync from 'react-use/esm/useAsync';
12
+ import { useApi } from '@backstage/core-plugin-api';
13
+ import { DataValueGridItem } from '../DataValue/DataValue.esm.js';
14
+ import { sumField, getValues } from '../../utils/array.esm.js';
15
+ import { getAverageDuration, getErrorRatios } from '../../utils/buildData.esm.js';
16
+ import { formatPercentage, formatDuration } from '../../utils/format.esm.js';
17
+
18
+ const useStyles = makeStyles({
19
+ spacingTop: {
20
+ marginTop: 8
21
+ },
22
+ spacingVertical: {
23
+ marginTop: 8,
24
+ marginBottom: 8
25
+ }
26
+ });
27
+ const DAYS_SELECT_ITEMS = [
28
+ { label: "7 days", value: 7 },
29
+ { label: "14 days", value: 14 },
30
+ { label: "30 days", value: 30 },
31
+ { label: "60 days", value: 60 }
32
+ ];
33
+ const OverviewTrends = () => {
34
+ const [days, setDays] = useState(14);
35
+ const theme = useTheme();
36
+ const classes = useStyles();
37
+ const client = useApi(xcmetricsApiRef);
38
+ const buildCountsResult = useAsync(
39
+ async () => client.getBuildCounts(days),
40
+ [days]
41
+ );
42
+ const buildTimesResult = useAsync(
43
+ async () => client.getBuildTimes(days),
44
+ [days]
45
+ );
46
+ if (buildCountsResult.loading && buildTimesResult.loading) {
47
+ return /* @__PURE__ */ React.createElement(Progress, null);
48
+ }
49
+ const sumBuilds = sumField((b) => b.builds, buildCountsResult.value);
50
+ const sumErrors = sumField((b) => b.errors, buildCountsResult.value);
51
+ const errorRate = sumBuilds && sumErrors ? sumErrors / sumBuilds : void 0;
52
+ const averageBuildDurationP50 = getAverageDuration(
53
+ buildTimesResult.value,
54
+ (b) => b.durationP50
55
+ );
56
+ const averageBuildDurationP95 = getAverageDuration(
57
+ buildTimesResult.value,
58
+ (b) => b.durationP95
59
+ );
60
+ const totalBuildTime = sumField((t) => t.totalDuration, buildTimesResult.value);
61
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
62
+ Select,
63
+ {
64
+ selected: days,
65
+ items: DAYS_SELECT_ITEMS,
66
+ label: "Trends for",
67
+ onChange: (selection) => setDays(selection)
68
+ }
69
+ ), buildCountsResult.error && /* @__PURE__ */ React.createElement(Alert, { severity: "error", className: classes.spacingVertical }, /* @__PURE__ */ React.createElement(AlertTitle, null, "Failed to fetch build counts"), buildCountsResult?.error?.message), buildTimesResult.error && /* @__PURE__ */ React.createElement(Alert, { severity: "error", className: classes.spacingVertical }, /* @__PURE__ */ React.createElement(AlertTitle, null, "Failed to fetch build times"), buildTimesResult?.error?.message), (!buildCountsResult.error || !buildTimesResult.error) && /* @__PURE__ */ React.createElement("div", { className: classes.spacingVertical }, /* @__PURE__ */ React.createElement(
70
+ Trend,
71
+ {
72
+ title: "Build Time",
73
+ color: theme.palette.secondary.main,
74
+ data: getValues((e) => e.durationP50, buildTimesResult.value)
75
+ }
76
+ ), /* @__PURE__ */ React.createElement(
77
+ Trend,
78
+ {
79
+ title: "Error Rate",
80
+ color: theme.palette.status.warning,
81
+ data: getErrorRatios(buildCountsResult.value)
82
+ }
83
+ ), /* @__PURE__ */ React.createElement(
84
+ Trend,
85
+ {
86
+ title: "Build Count",
87
+ color: theme.palette.primary.main,
88
+ data: getValues((e) => e.builds, buildCountsResult.value)
89
+ }
90
+ ), /* @__PURE__ */ React.createElement(
91
+ Grid,
92
+ {
93
+ container: true,
94
+ spacing: 3,
95
+ direction: "row",
96
+ className: classes.spacingTop
97
+ },
98
+ /* @__PURE__ */ React.createElement(DataValueGridItem, { field: "Build Count", value: sumBuilds }),
99
+ /* @__PURE__ */ React.createElement(DataValueGridItem, { field: "Error Count", value: sumErrors }),
100
+ /* @__PURE__ */ React.createElement(
101
+ DataValueGridItem,
102
+ {
103
+ field: "Error Rate",
104
+ value: errorRate && formatPercentage(errorRate)
105
+ }
106
+ ),
107
+ /* @__PURE__ */ React.createElement(
108
+ DataValueGridItem,
109
+ {
110
+ field: "Avg. Build Time (P50)",
111
+ value: averageBuildDurationP50
112
+ }
113
+ ),
114
+ /* @__PURE__ */ React.createElement(
115
+ DataValueGridItem,
116
+ {
117
+ field: "Avg. Build Time (P95)",
118
+ value: averageBuildDurationP95
119
+ }
120
+ ),
121
+ /* @__PURE__ */ React.createElement(
122
+ DataValueGridItem,
123
+ {
124
+ field: "Total Build Time",
125
+ value: totalBuildTime && formatDuration(totalBuildTime)
126
+ }
127
+ )
128
+ )));
129
+ };
130
+
131
+ export { OverviewTrends };
132
+ //# sourceMappingURL=OverviewTrends.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OverviewTrends.esm.js","sources":["../../../src/components/OverviewTrends/OverviewTrends.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 Grid from '@material-ui/core/Grid';\nimport { makeStyles, useTheme } from '@material-ui/core/styles';\nimport React, { useState } from 'react';\nimport { Progress, Select } from '@backstage/core-components';\nimport { Trend } from '../Trend';\nimport Alert from '@material-ui/lab/Alert';\nimport AlertTitle from '@material-ui/lab/AlertTitle';\nimport { xcmetricsApiRef } from '../../api';\nimport useAsync from 'react-use/esm/useAsync';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { DataValueGridItem } from '../DataValue';\nimport {\n formatDuration,\n formatPercentage,\n getAverageDuration,\n getErrorRatios,\n getValues,\n sumField,\n} from '../../utils';\n\nconst useStyles = makeStyles({\n spacingTop: {\n marginTop: 8,\n },\n spacingVertical: {\n marginTop: 8,\n marginBottom: 8,\n },\n});\n\nconst DAYS_SELECT_ITEMS = [\n { label: '7 days', value: 7 },\n { label: '14 days', value: 14 },\n { label: '30 days', value: 30 },\n { label: '60 days', value: 60 },\n];\n\nexport const OverviewTrends = () => {\n const [days, setDays] = useState(14);\n const theme = useTheme();\n const classes = useStyles();\n const client = useApi(xcmetricsApiRef);\n const buildCountsResult = useAsync(\n async () => client.getBuildCounts(days),\n [days],\n );\n const buildTimesResult = useAsync(\n async () => client.getBuildTimes(days),\n [days],\n );\n\n if (buildCountsResult.loading && buildTimesResult.loading) {\n return <Progress />;\n }\n\n const sumBuilds = sumField(b => b.builds, buildCountsResult.value);\n const sumErrors = sumField(b => b.errors, buildCountsResult.value);\n const errorRate = sumBuilds && sumErrors ? sumErrors / sumBuilds : undefined;\n\n const averageBuildDurationP50 = getAverageDuration(\n buildTimesResult.value,\n b => b.durationP50,\n );\n const averageBuildDurationP95 = getAverageDuration(\n buildTimesResult.value,\n b => b.durationP95,\n );\n const totalBuildTime = sumField(t => t.totalDuration, buildTimesResult.value);\n\n return (\n <>\n <Select\n selected={days}\n items={DAYS_SELECT_ITEMS}\n label=\"Trends for\"\n onChange={selection => setDays(selection as number)}\n />\n {buildCountsResult.error && (\n <Alert severity=\"error\" className={classes.spacingVertical}>\n <AlertTitle>Failed to fetch build counts</AlertTitle>\n {buildCountsResult?.error?.message}\n </Alert>\n )}\n {buildTimesResult.error && (\n <Alert severity=\"error\" className={classes.spacingVertical}>\n <AlertTitle>Failed to fetch build times</AlertTitle>\n {buildTimesResult?.error?.message}\n </Alert>\n )}\n {(!buildCountsResult.error || !buildTimesResult.error) && (\n <div className={classes.spacingVertical}>\n <Trend\n title=\"Build Time\"\n color={theme.palette.secondary.main}\n data={getValues(e => e.durationP50, buildTimesResult.value)}\n />\n <Trend\n title=\"Error Rate\"\n color={theme.palette.status.warning}\n data={getErrorRatios(buildCountsResult.value)}\n />\n <Trend\n title=\"Build Count\"\n color={theme.palette.primary.main}\n data={getValues(e => e.builds, buildCountsResult.value)}\n />\n <Grid\n container\n spacing={3}\n direction=\"row\"\n className={classes.spacingTop}\n >\n <DataValueGridItem field=\"Build Count\" value={sumBuilds} />\n <DataValueGridItem field=\"Error Count\" value={sumErrors} />\n <DataValueGridItem\n field=\"Error Rate\"\n value={errorRate && formatPercentage(errorRate)}\n />\n <DataValueGridItem\n field=\"Avg. Build Time (P50)\"\n value={averageBuildDurationP50}\n />\n <DataValueGridItem\n field=\"Avg. Build Time (P95)\"\n value={averageBuildDurationP95}\n />\n <DataValueGridItem\n field=\"Total Build Time\"\n value={totalBuildTime && formatDuration(totalBuildTime)}\n />\n </Grid>\n </div>\n )}\n </>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,81 @@
1
+ import Button from '@material-ui/core/Button';
2
+ import Dialog from '@material-ui/core/Dialog';
3
+ import DialogActions from '@material-ui/core/DialogActions';
4
+ import DialogContent from '@material-ui/core/DialogContent';
5
+ import DialogTitle from '@material-ui/core/DialogTitle';
6
+ import IconButton from '@material-ui/core/IconButton';
7
+ import { makeStyles, createStyles } from '@material-ui/core/styles';
8
+ import CloseIcon from '@material-ui/icons/Close';
9
+ import React, { useState } from 'react';
10
+ import 'luxon';
11
+ import 'lodash/upperFirst';
12
+ import { cn } from '../../utils/classnames.esm.js';
13
+
14
+ const useStyles = makeStyles(
15
+ (theme) => createStyles({
16
+ pre: {
17
+ whiteSpace: "pre-line",
18
+ wordBreak: "break-all"
19
+ },
20
+ expandable: {
21
+ cursor: "pointer"
22
+ },
23
+ fullPre: {
24
+ whiteSpace: "pre-wrap"
25
+ },
26
+ closeButton: {
27
+ position: "absolute",
28
+ right: theme.spacing(1),
29
+ top: theme.spacing(1),
30
+ color: theme.palette.grey[500]
31
+ }
32
+ })
33
+ );
34
+ const PreformattedText = ({
35
+ text,
36
+ maxChars,
37
+ expandable,
38
+ title
39
+ }) => {
40
+ const [open, setOpen] = useState(false);
41
+ const classes = useStyles();
42
+ const handleKeyUp = (event) => {
43
+ if (expandable && event.key === "Enter") {
44
+ setOpen(true);
45
+ }
46
+ };
47
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
48
+ "div",
49
+ {
50
+ role: expandable ? "button" : void 0,
51
+ onClick: () => expandable && setOpen(true),
52
+ onKeyUp: handleKeyUp,
53
+ tabIndex: expandable ? 0 : void 0
54
+ },
55
+ /* @__PURE__ */ React.createElement("pre", { className: cn(classes.pre, expandable && classes.expandable) }, text.slice(0, maxChars - 1).trim(), text.length > maxChars - 1 && "\u2026")
56
+ ), expandable && /* @__PURE__ */ React.createElement(
57
+ Dialog,
58
+ {
59
+ open,
60
+ onClose: () => setOpen(false),
61
+ "aria-labelledby": "dialog-title",
62
+ "aria-describedby": "dialog-description",
63
+ maxWidth: "xl",
64
+ fullWidth: true
65
+ },
66
+ /* @__PURE__ */ React.createElement(DialogTitle, { id: "dialog-title" }, title, /* @__PURE__ */ React.createElement(
67
+ IconButton,
68
+ {
69
+ "aria-label": "close",
70
+ className: classes.closeButton,
71
+ onClick: () => setOpen(false)
72
+ },
73
+ /* @__PURE__ */ React.createElement(CloseIcon, null)
74
+ )),
75
+ /* @__PURE__ */ React.createElement(DialogContent, null, /* @__PURE__ */ React.createElement("pre", { className: classes.fullPre }, text)),
76
+ /* @__PURE__ */ React.createElement(DialogActions, null, /* @__PURE__ */ React.createElement(Button, { color: "primary", onClick: () => setOpen(false) }, "Close"))
77
+ ));
78
+ };
79
+
80
+ export { PreformattedText };
81
+ //# sourceMappingURL=PreformattedText.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PreformattedText.esm.js","sources":["../../../src/components/PreformattedText/PreformattedText.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 Button from '@material-ui/core/Button';\nimport Dialog from '@material-ui/core/Dialog';\nimport DialogActions from '@material-ui/core/DialogActions';\nimport DialogContent from '@material-ui/core/DialogContent';\nimport DialogTitle from '@material-ui/core/DialogTitle';\nimport IconButton from '@material-ui/core/IconButton';\nimport { createStyles, makeStyles } from '@material-ui/core/styles';\nimport CloseIcon from '@material-ui/icons/Close';\nimport React, { useState } from 'react';\nimport { cn } from '../../utils';\n\nconst useStyles = makeStyles(theme =>\n createStyles({\n pre: {\n whiteSpace: 'pre-line',\n wordBreak: 'break-all',\n },\n expandable: {\n cursor: 'pointer',\n },\n fullPre: {\n whiteSpace: 'pre-wrap',\n },\n closeButton: {\n position: 'absolute',\n right: theme.spacing(1),\n top: theme.spacing(1),\n color: theme.palette.grey[500],\n },\n }),\n);\n\ninterface PreformattedTextProps {\n text: string;\n maxChars: number;\n}\n\ninterface ExpandableProps extends PreformattedTextProps {\n expandable: boolean;\n title: string;\n}\n\ninterface NonExpandableProps extends PreformattedTextProps {\n expandable?: never;\n title?: string;\n}\n\nexport const PreformattedText = ({\n text,\n maxChars,\n expandable,\n title,\n}: NonExpandableProps | ExpandableProps) => {\n const [open, setOpen] = useState(false);\n const classes = useStyles();\n\n const handleKeyUp = (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (expandable && event.key === 'Enter') {\n setOpen(true);\n }\n };\n\n return (\n <>\n <div\n role={expandable ? 'button' : undefined}\n onClick={() => expandable && setOpen(true)}\n onKeyUp={handleKeyUp}\n tabIndex={expandable ? 0 : undefined}\n >\n <pre className={cn(classes.pre, expandable && classes.expandable)}>\n {text.slice(0, maxChars - 1).trim()}\n {text.length > maxChars - 1 && '…'}\n </pre>\n </div>\n\n {expandable && (\n <Dialog\n open={open}\n onClose={() => setOpen(false)}\n aria-labelledby=\"dialog-title\"\n aria-describedby=\"dialog-description\"\n maxWidth=\"xl\"\n fullWidth\n >\n <DialogTitle id=\"dialog-title\">\n {title}\n <IconButton\n aria-label=\"close\"\n className={classes.closeButton}\n onClick={() => setOpen(false)}\n >\n <CloseIcon />\n </IconButton>\n </DialogTitle>\n <DialogContent>\n <pre className={classes.fullPre}>{text}</pre>\n </DialogContent>\n <DialogActions>\n <Button color=\"primary\" onClick={() => setOpen(false)}>\n Close\n </Button>\n </DialogActions>\n </Dialog>\n )}\n </>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ import Tooltip from '@material-ui/core/Tooltip';
2
+ import { makeStyles } from '@material-ui/core/styles';
3
+ import React from 'react';
4
+ import { xcmetricsApiRef } from '../../api/types.esm.js';
5
+ import '@backstage/errors';
6
+ import 'luxon';
7
+ import { formatDuration, formatStatus } from '../../utils/format.esm.js';
8
+ import { cn } from '../../utils/classnames.esm.js';
9
+ import useAsync from 'react-use/esm/useAsync';
10
+ import { useApi } from '@backstage/core-plugin-api';
11
+ import { Progress } from '@backstage/core-components';
12
+
13
+ const TooltipContent = ({ buildId }) => {
14
+ const client = useApi(xcmetricsApiRef);
15
+ const { value, loading, error } = useAsync(
16
+ async () => client.getBuild(buildId),
17
+ []
18
+ );
19
+ if (error) {
20
+ return /* @__PURE__ */ React.createElement("div", null, error.message);
21
+ }
22
+ if (loading || !value?.build) {
23
+ return /* @__PURE__ */ React.createElement(Progress, { style: { width: 100 } });
24
+ }
25
+ return /* @__PURE__ */ React.createElement("table", null, /* @__PURE__ */ React.createElement("tbody", null, /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("td", null, "Started"), /* @__PURE__ */ React.createElement("td", null, new Date(value.build.startTimestamp).toLocaleString())), /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("td", null, "Duration"), /* @__PURE__ */ React.createElement("td", null, formatDuration(value.build.duration))), /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("td", null, "Status"), /* @__PURE__ */ React.createElement("td", null, formatStatus(value.build.buildStatus)))));
26
+ };
27
+ const useStyles = makeStyles((theme) => ({
28
+ root: {
29
+ width: ({ size }) => size,
30
+ height: ({ size }) => size,
31
+ marginRight: ({ spacing }) => spacing,
32
+ marginBottom: ({ spacing }) => spacing,
33
+ backgroundColor: theme.palette.grey[600],
34
+ "&:hover": {
35
+ transform: "scale(1.2)"
36
+ }
37
+ },
38
+ ...{
39
+ succeeded: {
40
+ backgroundColor: theme.palette.type === "light" ? theme.palette.success.light : theme.palette.success.main
41
+ }
42
+ },
43
+ // Make sure that key matches a status
44
+ ...{
45
+ failed: {
46
+ backgroundColor: theme.palette.error[theme.palette.type]
47
+ }
48
+ },
49
+ ...{
50
+ stopped: {
51
+ backgroundColor: theme.palette.warning[theme.palette.type]
52
+ }
53
+ }
54
+ }));
55
+ const StatusCell = (props) => {
56
+ const classes = useStyles(props);
57
+ const { buildStatus } = props;
58
+ if (!buildStatus) {
59
+ return /* @__PURE__ */ React.createElement("div", { className: classes.root });
60
+ }
61
+ return /* @__PURE__ */ React.createElement(
62
+ Tooltip,
63
+ {
64
+ title: /* @__PURE__ */ React.createElement(TooltipContent, { buildId: buildStatus.id }),
65
+ enterNextDelay: 500,
66
+ arrow: true
67
+ },
68
+ /* @__PURE__ */ React.createElement(
69
+ "div",
70
+ {
71
+ "data-testid": buildStatus.id,
72
+ className: cn(classes.root, classes[buildStatus.buildStatus])
73
+ }
74
+ )
75
+ );
76
+ };
77
+
78
+ export { StatusCell };
79
+ //# sourceMappingURL=StatusCell.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StatusCell.esm.js","sources":["../../../src/components/StatusCell/StatusCell.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 Tooltip from '@material-ui/core/Tooltip';\nimport { makeStyles, Theme } from '@material-ui/core/styles';\nimport React from 'react';\nimport { BuildStatus, BuildStatusResult, xcmetricsApiRef } from '../../api';\nimport { cn, formatDuration, formatStatus } from '../../utils';\nimport useAsync from 'react-use/esm/useAsync';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { Progress } from '@backstage/core-components';\n\ninterface TooltipContentProps {\n buildId: string;\n}\n\nconst TooltipContent = ({ buildId }: TooltipContentProps) => {\n const client = useApi(xcmetricsApiRef);\n const { value, loading, error } = useAsync(\n async () => client.getBuild(buildId),\n [],\n );\n\n if (error) {\n return <div>{error.message}</div>;\n }\n\n if (loading || !value?.build) {\n return <Progress style={{ width: 100 }} />;\n }\n\n return (\n <table>\n <tbody>\n <tr>\n <td>Started</td>\n <td>{new Date(value.build.startTimestamp).toLocaleString()}</td>\n </tr>\n <tr>\n <td>Duration</td>\n <td>{formatDuration(value.build.duration)}</td>\n </tr>\n <tr>\n <td>Status</td>\n <td>{formatStatus(value.build.buildStatus)}</td>\n </tr>\n </tbody>\n </table>\n );\n};\n\ninterface StatusCellProps {\n buildStatus?: BuildStatusResult;\n size: number;\n spacing: number;\n}\n\ntype StatusStyle = {\n [key in BuildStatus]: any;\n};\n\nconst useStyles = makeStyles<Theme, StatusCellProps>(theme => ({\n root: {\n width: ({ size }) => size,\n height: ({ size }) => size,\n marginRight: ({ spacing }) => spacing,\n marginBottom: ({ spacing }) => spacing,\n backgroundColor: theme.palette.grey[600],\n '&:hover': {\n transform: 'scale(1.2)',\n },\n },\n ...({\n succeeded: {\n backgroundColor:\n theme.palette.type === 'light'\n ? theme.palette.success.light\n : theme.palette.success.main,\n },\n } as StatusStyle), // Make sure that key matches a status\n ...({\n failed: {\n backgroundColor: theme.palette.error[theme.palette.type],\n },\n } as StatusStyle),\n ...({\n stopped: {\n backgroundColor: theme.palette.warning[theme.palette.type],\n },\n } as StatusStyle),\n}));\n\nexport const StatusCell = (props: StatusCellProps) => {\n const classes = useStyles(props);\n const { buildStatus } = props;\n\n if (!buildStatus) {\n return <div className={classes.root} />;\n }\n\n return (\n <Tooltip\n title={<TooltipContent buildId={buildStatus.id} />}\n enterNextDelay={500}\n arrow\n >\n <div\n data-testid={buildStatus.id}\n className={cn(classes.root, classes[buildStatus.buildStatus])}\n />\n </Tooltip>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;;AA6BA,MAAM,cAAiB,GAAA,CAAC,EAAE,OAAA,EAAmC,KAAA;AAC3D,EAAM,MAAA,MAAA,GAAS,OAAO,eAAe,CAAA,CAAA;AACrC,EAAA,MAAM,EAAE,KAAA,EAAO,OAAS,EAAA,KAAA,EAAU,GAAA,QAAA;AAAA,IAChC,YAAY,MAAO,CAAA,QAAA,CAAS,OAAO,CAAA;AAAA,IACnC,EAAC;AAAA,GACH,CAAA;AAEA,EAAA,IAAI,KAAO,EAAA;AACT,IAAO,uBAAA,KAAA,CAAA,aAAA,CAAC,KAAK,EAAA,IAAA,EAAA,KAAA,CAAM,OAAQ,CAAA,CAAA;AAAA,GAC7B;AAEA,EAAI,IAAA,OAAA,IAAW,CAAC,KAAA,EAAO,KAAO,EAAA;AAC5B,IAAA,2CAAQ,QAAS,EAAA,EAAA,KAAA,EAAO,EAAE,KAAA,EAAO,KAAO,EAAA,CAAA,CAAA;AAAA,GAC1C;AAEA,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,OACC,EAAA,IAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,OACC,EAAA,IAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,4BACE,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,IAAA,EAAG,SAAO,CAAA,kBACV,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,IAAA,EAAI,IAAI,IAAK,CAAA,KAAA,CAAM,KAAM,CAAA,cAAc,CAAE,CAAA,cAAA,EAAiB,CAC7D,CAAA,kBACC,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,IAAA,kBACE,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,IAAA,EAAG,UAAQ,CACZ,kBAAA,KAAA,CAAA,aAAA,CAAC,IAAI,EAAA,IAAA,EAAA,cAAA,CAAe,KAAM,CAAA,KAAA,CAAM,QAAQ,CAAE,CAC5C,CACA,kBAAA,KAAA,CAAA,aAAA,CAAC,IACC,EAAA,IAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,YAAG,QAAM,CAAA,kBACT,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,IAAA,EAAI,YAAa,CAAA,KAAA,CAAM,MAAM,WAAW,CAAE,CAC7C,CACF,CACF,CAAA,CAAA;AAEJ,CAAA,CAAA;AAYA,MAAM,SAAA,GAAY,WAAmC,CAAU,KAAA,MAAA;AAAA,EAC7D,IAAM,EAAA;AAAA,IACJ,KAAO,EAAA,CAAC,EAAE,IAAA,EAAW,KAAA,IAAA;AAAA,IACrB,MAAQ,EAAA,CAAC,EAAE,IAAA,EAAW,KAAA,IAAA;AAAA,IACtB,WAAa,EAAA,CAAC,EAAE,OAAA,EAAc,KAAA,OAAA;AAAA,IAC9B,YAAc,EAAA,CAAC,EAAE,OAAA,EAAc,KAAA,OAAA;AAAA,IAC/B,eAAiB,EAAA,KAAA,CAAM,OAAQ,CAAA,IAAA,CAAK,GAAG,CAAA;AAAA,IACvC,SAAW,EAAA;AAAA,MACT,SAAW,EAAA,YAAA;AAAA,KACb;AAAA,GACF;AAAA,EACA,GAAI;AAAA,IACF,SAAW,EAAA;AAAA,MACT,eAAA,EACE,KAAM,CAAA,OAAA,CAAQ,IAAS,KAAA,OAAA,GACnB,KAAM,CAAA,OAAA,CAAQ,OAAQ,CAAA,KAAA,GACtB,KAAM,CAAA,OAAA,CAAQ,OAAQ,CAAA,IAAA;AAAA,KAC9B;AAAA,GACF;AAAA;AAAA,EACA,GAAI;AAAA,IACF,MAAQ,EAAA;AAAA,MACN,iBAAiB,KAAM,CAAA,OAAA,CAAQ,KAAM,CAAA,KAAA,CAAM,QAAQ,IAAI,CAAA;AAAA,KACzD;AAAA,GACF;AAAA,EACA,GAAI;AAAA,IACF,OAAS,EAAA;AAAA,MACP,iBAAiB,KAAM,CAAA,OAAA,CAAQ,OAAQ,CAAA,KAAA,CAAM,QAAQ,IAAI,CAAA;AAAA,KAC3D;AAAA,GACF;AACF,CAAE,CAAA,CAAA,CAAA;AAEW,MAAA,UAAA,GAAa,CAAC,KAA2B,KAAA;AACpD,EAAM,MAAA,OAAA,GAAU,UAAU,KAAK,CAAA,CAAA;AAC/B,EAAM,MAAA,EAAE,aAAgB,GAAA,KAAA,CAAA;AAExB,EAAA,IAAI,CAAC,WAAa,EAAA;AAChB,IAAA,uBAAQ,KAAA,CAAA,aAAA,CAAA,KAAA,EAAA,EAAI,SAAW,EAAA,OAAA,CAAQ,IAAM,EAAA,CAAA,CAAA;AAAA,GACvC;AAEA,EACE,uBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACC,KAAO,kBAAA,KAAA,CAAA,aAAA,CAAC,cAAe,EAAA,EAAA,OAAA,EAAS,YAAY,EAAI,EAAA,CAAA;AAAA,MAChD,cAAgB,EAAA,GAAA;AAAA,MAChB,KAAK,EAAA,IAAA;AAAA,KAAA;AAAA,oBAEL,KAAA,CAAA,aAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,eAAa,WAAY,CAAA,EAAA;AAAA,QACzB,WAAW,EAAG,CAAA,OAAA,CAAQ,MAAM,OAAQ,CAAA,WAAA,CAAY,WAAW,CAAC,CAAA;AAAA,OAAA;AAAA,KAC9D;AAAA,GACF,CAAA;AAEJ;;;;"}
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import { StatusAborted, StatusOK, StatusError, StatusWarning } from '@backstage/core-components';
3
+
4
+ const STATUS_ICONS = {
5
+ succeeded: /* @__PURE__ */ React.createElement(StatusOK, null),
6
+ failed: /* @__PURE__ */ React.createElement(StatusError, null),
7
+ stopped: /* @__PURE__ */ React.createElement(StatusWarning, null)
8
+ };
9
+ const StatusIcon = ({ buildStatus }) => STATUS_ICONS[buildStatus] ?? /* @__PURE__ */ React.createElement(StatusAborted, null);
10
+
11
+ export { StatusIcon };
12
+ //# sourceMappingURL=StatusIcon.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StatusIcon.esm.js","sources":["../../../src/components/StatusIcon/StatusIcon.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 */\nimport React from 'react';\nimport {\n StatusAborted,\n StatusError,\n StatusOK,\n StatusWarning,\n} from '@backstage/core-components';\nimport { BuildStatus } from '../../api';\n\nconst STATUS_ICONS: { [key in BuildStatus]: JSX.Element } = {\n succeeded: <StatusOK />,\n failed: <StatusError />,\n stopped: <StatusWarning />,\n};\n\ninterface StatusIconProps {\n buildStatus: BuildStatus;\n}\n\nexport const StatusIcon = ({ buildStatus }: StatusIconProps) =>\n STATUS_ICONS[buildStatus] ?? <StatusAborted />;\n"],"names":[],"mappings":";;;AAwBA,MAAM,YAAsD,GAAA;AAAA,EAC1D,SAAA,sCAAY,QAAS,EAAA,IAAA,CAAA;AAAA,EACrB,MAAA,sCAAS,WAAY,EAAA,IAAA,CAAA;AAAA,EACrB,OAAA,sCAAU,aAAc,EAAA,IAAA,CAAA;AAC1B,CAAA,CAAA;AAMa,MAAA,UAAA,GAAa,CAAC,EAAE,WAAA,OAC3B,YAAa,CAAA,WAAW,CAAK,oBAAA,KAAA,CAAA,aAAA,CAAC,aAAc,EAAA,IAAA;;;;"}