@backstage/plugin-techdocs 0.12.5 → 0.12.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.
package/dist/index.esm.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { createApiRef, createRouteRef, useRouteRef, useApi, configApiRef, createPlugin, createApiFactory, discoveryApiRef, identityApiRef, createRoutableExtension, createComponentExtension } from '@backstage/core-plugin-api';
2
2
  import { ResponseError, NotFoundError } from '@backstage/errors';
3
3
  import { EventSourcePolyfill } from 'event-source-polyfill';
4
- import React, { useEffect, useState, Suspense, useReducer, useRef, useMemo, useContext, createContext, useCallback } from 'react';
4
+ import React, { useEffect, useState, useReducer, useRef, useMemo, createContext, useContext, useCallback } from 'react';
5
5
  import { makeStyles, ListItemText, ListItem, Divider, Card, CardMedia, CardContent, CardActions, Grid, TextField, InputAdornment, IconButton, CircularProgress, createStyles, Button as Button$1, Drawer, Typography, useTheme } from '@material-ui/core';
6
- import { Link, SubvalueCell, Table, EmptyState, Button, WarningPanel, CodeSnippet, PageWithHeader, Content, ContentHeader, SupportButton, ItemCardGrid, ItemCardHeader, Progress, ErrorPage, HeaderLabel, Header, Page, HeaderTabs, MissingAnnotationEmptyState } from '@backstage/core-components';
6
+ import { Link, SubvalueCell, Table, EmptyState, Button, WarningPanel, CodeSnippet, PageWithHeader, Content, ContentHeader, SupportButton, ItemCardGrid, ItemCardHeader, Progress, LogViewer, ErrorPage, HeaderLabel, Header, Page, HeaderTabs, MissingAnnotationEmptyState } from '@backstage/core-components';
7
7
  import TextTruncate from 'react-text-truncate';
8
8
  import { FilteredEntityLayout, FilterContainer, EntityListContainer } from '@backstage/plugin-catalog';
9
9
  import { favoriteEntityIcon, favoriteEntityTooltip, EntityRefLinks, getEntityRelations, formatEntityRefTitle, useEntityListProvider, useStarredEntities, CATALOG_FILTER_EXISTS, EntityListProvider, UserListPicker, EntityOwnerPicker, EntityTagPicker, EntityRefLink, catalogApiRef, useOwnUser, isOwnerOf, useEntity } from '@backstage/plugin-catalog-react';
@@ -50,12 +50,12 @@ class TechDocsClient {
50
50
  return (_a = this.configApi.getOptionalString("techdocs.requestUrl")) != null ? _a : await this.discoveryApi.getBaseUrl("techdocs");
51
51
  }
52
52
  async getTechDocsMetadata(entityId) {
53
- const {kind, namespace, name} = entityId;
53
+ const { kind, namespace, name } = entityId;
54
54
  const apiOrigin = await this.getApiOrigin();
55
55
  const requestUrl = `${apiOrigin}/metadata/techdocs/${namespace}/${kind}/${name}`;
56
56
  const token = await this.identityApi.getIdToken();
57
57
  const request = await fetch(`${requestUrl}`, {
58
- headers: token ? {Authorization: `Bearer ${token}`} : {}
58
+ headers: token ? { Authorization: `Bearer ${token}` } : {}
59
59
  });
60
60
  if (!request.ok) {
61
61
  throw await ResponseError.fromResponse(request);
@@ -63,12 +63,12 @@ class TechDocsClient {
63
63
  return await request.json();
64
64
  }
65
65
  async getEntityMetadata(entityId) {
66
- const {kind, namespace, name} = entityId;
66
+ const { kind, namespace, name } = entityId;
67
67
  const apiOrigin = await this.getApiOrigin();
68
68
  const requestUrl = `${apiOrigin}/metadata/entity/${namespace}/${kind}/${name}`;
69
69
  const token = await this.identityApi.getIdToken();
70
70
  const request = await fetch(`${requestUrl}`, {
71
- headers: token ? {Authorization: `Bearer ${token}`} : {}
71
+ headers: token ? { Authorization: `Bearer ${token}` } : {}
72
72
  });
73
73
  if (!request.ok) {
74
74
  throw await ResponseError.fromResponse(request);
@@ -98,12 +98,12 @@ class TechDocsStorageClient {
98
98
  return this.configApi.getString("techdocs.builder");
99
99
  }
100
100
  async getEntityDocs(entityId, path) {
101
- const {kind, namespace, name} = entityId;
101
+ const { kind, namespace, name } = entityId;
102
102
  const storageUrl = await this.getStorageUrl();
103
103
  const url = `${storageUrl}/${namespace}/${kind}/${name}/${path}`;
104
104
  const token = await this.identityApi.getIdToken();
105
105
  const request = await fetch(`${url.endsWith("/") ? url : `${url}/`}index.html`, {
106
- headers: token ? {Authorization: `Bearer ${token}`} : {}
106
+ headers: token ? { Authorization: `Bearer ${token}` } : {}
107
107
  });
108
108
  let errorMessage = "";
109
109
  switch (request.status) {
@@ -121,14 +121,14 @@ class TechDocsStorageClient {
121
121
  }
122
122
  async syncEntityDocs(entityId, logHandler = () => {
123
123
  }) {
124
- const {kind, namespace, name} = entityId;
124
+ const { kind, namespace, name } = entityId;
125
125
  const apiOrigin = await this.getApiOrigin();
126
126
  const url = `${apiOrigin}/sync/${namespace}/${kind}/${name}`;
127
127
  const token = await this.identityApi.getIdToken();
128
128
  return new Promise((resolve, reject) => {
129
129
  const source = new EventSourcePolyfill(url, {
130
130
  withCredentials: true,
131
- headers: token ? {Authorization: `Bearer ${token}`} : {}
131
+ headers: token ? { Authorization: `Bearer ${token}` } : {}
132
132
  });
133
133
  source.addEventListener("log", (e) => {
134
134
  if (e.data) {
@@ -138,7 +138,7 @@ class TechDocsStorageClient {
138
138
  source.addEventListener("finish", (e) => {
139
139
  let updated = false;
140
140
  if (e.data) {
141
- ({updated} = JSON.parse(e.data));
141
+ ({ updated } = JSON.parse(e.data));
142
142
  }
143
143
  resolve(updated ? "updated" : "cached");
144
144
  });
@@ -156,7 +156,7 @@ class TechDocsStorageClient {
156
156
  });
157
157
  }
158
158
  async getBaseUrl(oldBaseUrl, entityId, path) {
159
- const {kind, namespace, name} = entityId;
159
+ const { kind, namespace, name } = entityId;
160
160
  const apiOrigin = await this.getApiOrigin();
161
161
  return new URL(oldBaseUrl, `${apiOrigin}/static/docs/${namespace}/${kind}/${name}/${path}`).toString();
162
162
  }
@@ -183,7 +183,7 @@ const DocsResultListItem = ({
183
183
  var _a;
184
184
  return /* @__PURE__ */ React.createElement(ListItemText, {
185
185
  className: classes.itemText,
186
- primaryTypographyProps: {variant: "h6"},
186
+ primaryTypographyProps: { variant: "h6" },
187
187
  primary: title ? title : `${result.title} | ${(_a = result.entityTitle) != null ? _a : result.name} docs`,
188
188
  secondary: /* @__PURE__ */ React.createElement(TextTruncate, {
189
189
  line: lineClamp,
@@ -193,10 +193,10 @@ const DocsResultListItem = ({
193
193
  })
194
194
  });
195
195
  };
196
- const LinkWrapper = ({children}) => asLink ? /* @__PURE__ */ React.createElement(Link, {
196
+ const LinkWrapper = ({ children }) => asLink ? /* @__PURE__ */ React.createElement(Link, {
197
197
  to: result.location
198
198
  }, children) : /* @__PURE__ */ React.createElement(React.Fragment, null, children);
199
- const ListItemWrapper = ({children}) => asListItem ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(ListItem, {
199
+ const ListItemWrapper = ({ children }) => asListItem ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(ListItem, {
200
200
  alignItems: "flex-start",
201
201
  className: classes.flexContainer
202
202
  }, children), /* @__PURE__ */ React.createElement(Divider, {
@@ -206,17 +206,14 @@ const DocsResultListItem = ({
206
206
  };
207
207
 
208
208
  const rootRouteRef = createRouteRef({
209
- id: "techdocs-index-page",
210
- title: "TechDocs Landing Page"
209
+ id: "techdocs:index-page"
211
210
  });
212
211
  const rootDocsRouteRef = createRouteRef({
213
- id: "techdocs-reader-page",
214
- title: "Docs",
212
+ id: "techdocs:reader-page",
215
213
  params: ["namespace", "kind", "name"]
216
214
  });
217
215
  const rootCatalogDocsRouteRef = createRouteRef({
218
- id: "catalog-techdocs-reader-view",
219
- title: "Docs"
216
+ id: "techdocs:catalog-reader-view"
220
217
  });
221
218
 
222
219
  function createCopyDocsUrlAction(copyToClipboard) {
@@ -231,10 +228,10 @@ function createCopyDocsUrlAction(copyToClipboard) {
231
228
  };
232
229
  }
233
230
  function createStarEntityAction(isStarredEntity, toggleStarredEntity) {
234
- return ({entity}) => {
231
+ return ({ entity }) => {
235
232
  const isStarred = isStarredEntity(entity);
236
233
  return {
237
- cellStyle: {paddingLeft: "1em"},
234
+ cellStyle: { paddingLeft: "1em" },
238
235
  icon: () => favoriteEntityIcon(isStarred),
239
236
  tooltip: favoriteEntityTooltip(isStarred),
240
237
  onClick: () => toggleStarredEntity(entity)
@@ -268,7 +265,7 @@ function createOwnerColumn() {
268
265
  return {
269
266
  title: "Owner",
270
267
  field: "resolved.ownedByRelationsTitle",
271
- render: ({resolved}) => /* @__PURE__ */ React.createElement(EntityRefLinks, {
268
+ render: ({ resolved }) => /* @__PURE__ */ React.createElement(EntityRefLinks, {
272
269
  entityRefs: resolved.ownedByRelations,
273
270
  defaultKind: "group"
274
271
  })
@@ -288,6 +285,10 @@ var columnFactories = /*#__PURE__*/Object.freeze({
288
285
  createTypeColumn: createTypeColumn
289
286
  });
290
287
 
288
+ function toLowerMaybe(str, config) {
289
+ return config.getOptionalBoolean("techdocs.legacyUseCaseSensitiveTripletPaths") ? str : str.toLocaleLowerCase("en-US");
290
+ }
291
+
291
292
  const DocsTable$1 = ({
292
293
  entities,
293
294
  title,
@@ -297,7 +298,7 @@ const DocsTable$1 = ({
297
298
  }) => {
298
299
  const [, copyToClipboard] = useCopyToClipboard();
299
300
  const getRouteToReaderPageFor = useRouteRef(rootDocsRouteRef);
300
- const toLowerMaybe = useApi(configApiRef).getOptionalBoolean("techdocs.legacyUseCaseSensitiveTripletPaths") ? (str) => str : (str) => str.toLocaleLowerCase();
301
+ const config = useApi(configApiRef);
301
302
  if (!entities)
302
303
  return null;
303
304
  const documents = entities.map((entity) => {
@@ -307,12 +308,12 @@ const DocsTable$1 = ({
307
308
  entity,
308
309
  resolved: {
309
310
  docsUrl: getRouteToReaderPageFor({
310
- namespace: toLowerMaybe((_a = entity.metadata.namespace) != null ? _a : "default"),
311
- kind: toLowerMaybe(entity.kind),
312
- name: toLowerMaybe(entity.metadata.name)
311
+ namespace: toLowerMaybe((_a = entity.metadata.namespace) != null ? _a : "default", config),
312
+ kind: toLowerMaybe(entity.kind, config),
313
+ name: toLowerMaybe(entity.metadata.name, config)
313
314
  }),
314
315
  ownedByRelations,
315
- ownedByRelationsTitle: ownedByRelations.map((r) => formatEntityRefTitle(r, {defaultKind: "group"})).join(", ")
316
+ ownedByRelationsTitle: ownedByRelations.map((r) => formatEntityRefTitle(r, { defaultKind: "group" })).join(", ")
316
317
  }
317
318
  };
318
319
  });
@@ -358,8 +359,8 @@ const EntityListDocsTable = ({
358
359
  actions
359
360
  }) => {
360
361
  var _a, _b;
361
- const {loading, error, entities, filters} = useEntityListProvider();
362
- const {isStarredEntity, toggleStarredEntity} = useStarredEntities();
362
+ const { loading, error, entities, filters } = useEntityListProvider();
363
+ const { isStarredEntity, toggleStarredEntity } = useStarredEntities();
363
364
  const [, copyToClipboard] = useCopyToClipboard();
364
365
  const title = capitalize((_b = (_a = filters.user) == null ? void 0 : _a.value) != null ? _b : "all");
365
366
  const defaultActions = [
@@ -386,7 +387,7 @@ const EntityListDocsTable = ({
386
387
  EntityListDocsTable.columns = columnFactories;
387
388
  EntityListDocsTable.actions = actionFactories;
388
389
 
389
- const TechDocsPageWrapper = ({children}) => {
390
+ const TechDocsPageWrapper = ({ children }) => {
390
391
  var _a;
391
392
  const configApi = useApi(configApiRef);
392
393
  const generatedSubtitle = `Documentation available in ${(_a = configApi.getOptionalString("organization.name")) != null ? _a : "Backstage"}`;
@@ -405,7 +406,7 @@ class TechDocsFilter {
405
406
  }
406
407
  }
407
408
  const TechDocsPicker = () => {
408
- const {updateFilters} = useEntityListProvider();
409
+ const { updateFilters } = useEntityListProvider();
409
410
  useEffect(() => {
410
411
  updateFilters({
411
412
  techdocs: new TechDocsFilter()
@@ -433,7 +434,7 @@ const DocsCardGrid$1 = ({
433
434
  entities
434
435
  }) => {
435
436
  const getRouteToReaderPageFor = useRouteRef(rootDocsRouteRef);
436
- const toLowerMaybe = useApi(configApiRef).getOptionalBoolean("techdocs.legacyUseCaseSensitiveTripletPaths") ? (str) => str : (str) => str.toLocaleLowerCase();
437
+ const config = useApi(configApiRef);
437
438
  if (!entities)
438
439
  return null;
439
440
  return /* @__PURE__ */ React.createElement(ItemCardGrid, {
@@ -446,9 +447,9 @@ const DocsCardGrid$1 = ({
446
447
  title: (_a = entity.metadata.title) != null ? _a : entity.metadata.name
447
448
  })), /* @__PURE__ */ React.createElement(CardContent, null, entity.metadata.description), /* @__PURE__ */ React.createElement(CardActions, null, /* @__PURE__ */ React.createElement(Button, {
448
449
  to: getRouteToReaderPageFor({
449
- namespace: toLowerMaybe((_b = entity.metadata.namespace) != null ? _b : "default"),
450
- kind: toLowerMaybe(entity.kind),
451
- name: toLowerMaybe(entity.metadata.name)
450
+ namespace: toLowerMaybe((_b = entity.metadata.namespace) != null ? _b : "default", config),
451
+ kind: toLowerMaybe(entity.kind, config),
452
+ name: toLowerMaybe(entity.metadata.name, config)
452
453
  }),
453
454
  color: "primary",
454
455
  "data-testid": "read_docs"
@@ -462,7 +463,7 @@ var DocsCardGrid$2 = /*#__PURE__*/Object.freeze({
462
463
  });
463
464
 
464
465
  const EntityListDocsGrid = () => {
465
- const {loading, error, entities} = useEntityListProvider();
466
+ const { loading, error, entities } = useEntityListProvider();
466
467
  if (error) {
467
468
  return /* @__PURE__ */ React.createElement(WarningPanel, {
468
469
  severity: "error",
@@ -494,7 +495,7 @@ const techdocsPlugin = createPlugin({
494
495
  discoveryApi: discoveryApiRef,
495
496
  identityApi: identityApiRef
496
497
  },
497
- factory: ({configApi, discoveryApi, identityApi}) => new TechDocsStorageClient({
498
+ factory: ({ configApi, discoveryApi, identityApi }) => new TechDocsStorageClient({
498
499
  configApi,
499
500
  discoveryApi,
500
501
  identityApi
@@ -507,7 +508,7 @@ const techdocsPlugin = createPlugin({
507
508
  discoveryApi: discoveryApiRef,
508
509
  identityApi: identityApiRef
509
510
  },
510
- factory: ({configApi, discoveryApi, identityApi}) => new TechDocsClient({
511
+ factory: ({ configApi, discoveryApi, identityApi }) => new TechDocsClient({
511
512
  configApi,
512
513
  discoveryApi,
513
514
  identityApi
@@ -580,7 +581,7 @@ const addBaseUrl = ({
580
581
  const newValue = await techdocsStorageApi.getBaseUrl(elemAttribute, entityId, path);
581
582
  if (isSvgNeedingInlining(attributeName, elemAttribute, apiOrigin)) {
582
583
  try {
583
- const svg = await fetch(newValue, {credentials: "include"});
584
+ const svg = await fetch(newValue, { credentials: "include" });
584
585
  const svgContent = await svg.text();
585
586
  elem.setAttribute(attributeName, `data:image/svg+xml;base64,${btoa(svgContent)}`);
586
587
  } catch (e) {
@@ -763,7 +764,7 @@ const sanitizeDOM = () => {
763
764
  };
764
765
  };
765
766
 
766
- const injectCss = ({css}) => {
767
+ const injectCss = ({ css }) => {
767
768
  return (dom) => {
768
769
  dom.getElementsByTagName("head")[0].insertAdjacentHTML("beforeend", `<style>${css}</style>`);
769
770
  return dom;
@@ -807,7 +808,7 @@ const TechDocsSearchBar = ({
807
808
  const {
808
809
  term,
809
810
  setTerm,
810
- result: {loading, value: searchVal}
811
+ result: { loading, value: searchVal }
811
812
  } = useSearch();
812
813
  const [options, setOptions] = useState([]);
813
814
  useEffect(() => {
@@ -830,7 +831,7 @@ const TechDocsSearchBar = ({
830
831
  };
831
832
  const handleSelection = (_, selection) => {
832
833
  if (selection == null ? void 0 : selection.document) {
833
- const {location} = selection.document;
834
+ const { location } = selection.document;
834
835
  navigate(location);
835
836
  }
836
837
  };
@@ -856,7 +857,7 @@ const TechDocsSearchBar = ({
856
857
  noOptionsText: "No results found",
857
858
  value: null,
858
859
  options,
859
- renderOption: ({document}) => /* @__PURE__ */ React.createElement(DocsResultListItem, {
860
+ renderOption: ({ document }) => /* @__PURE__ */ React.createElement(DocsResultListItem, {
860
861
  result: document,
861
862
  lineClamp: 3,
862
863
  asListItem: false,
@@ -902,7 +903,6 @@ const TechDocsSearch = (props) => {
902
903
  }));
903
904
  };
904
905
 
905
- const LazyLog = React.lazy(() => import('react-lazylog/build/LazyLog'));
906
906
  const useDrawerStyles = makeStyles((theme) => createStyles({
907
907
  paper: {
908
908
  width: "100%",
@@ -917,6 +917,9 @@ const useDrawerStyles = makeStyles((theme) => createStyles({
917
917
  root: {
918
918
  height: "100%",
919
919
  overflow: "hidden"
920
+ },
921
+ logs: {
922
+ background: theme.palette.background.default
920
923
  }
921
924
  }));
922
925
  const TechDocsBuildLogsDrawerContent = ({
@@ -924,6 +927,7 @@ const TechDocsBuildLogsDrawerContent = ({
924
927
  onClose
925
928
  }) => {
926
929
  const classes = useDrawerStyles();
930
+ const logText = buildLog.length === 0 ? "Waiting for logs..." : buildLog.join("\n");
927
931
  return /* @__PURE__ */ React.createElement(Grid, {
928
932
  container: true,
929
933
  direction: "column",
@@ -944,24 +948,19 @@ const TechDocsBuildLogsDrawerContent = ({
944
948
  title: "Close the drawer",
945
949
  onClick: onClose,
946
950
  color: "inherit"
947
- }, /* @__PURE__ */ React.createElement(Close, null))), /* @__PURE__ */ React.createElement(Suspense, {
948
- fallback: /* @__PURE__ */ React.createElement(Progress, null)
949
- }, /* @__PURE__ */ React.createElement(LazyLog, {
950
- text: buildLog.length === 0 ? "Waiting for logs..." : buildLog.join("\n"),
951
- extraLines: 1,
952
- follow: true,
953
- selectableLines: true,
954
- enableSearch: true
955
- })));
951
+ }, /* @__PURE__ */ React.createElement(Close, null))), /* @__PURE__ */ React.createElement(LogViewer, {
952
+ text: logText,
953
+ classes: { root: classes.logs }
954
+ }));
956
955
  };
957
- const TechDocsBuildLogs = ({buildLog}) => {
956
+ const TechDocsBuildLogs = ({ buildLog }) => {
958
957
  const classes = useDrawerStyles();
959
958
  const [open, setOpen] = useState(false);
960
959
  return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Button$1, {
961
960
  color: "inherit",
962
961
  onClick: () => setOpen(true)
963
962
  }, "Show Build Logs"), /* @__PURE__ */ React.createElement(Drawer, {
964
- classes: {paper: classes.paper},
963
+ classes: { paper: classes.paper },
965
964
  anchor: "right",
966
965
  open,
967
966
  onClose: () => setOpen(false)
@@ -971,7 +970,7 @@ const TechDocsBuildLogs = ({buildLog}) => {
971
970
  })));
972
971
  };
973
972
 
974
- const TechDocsNotFound = ({errorMessage}) => {
973
+ const TechDocsNotFound = ({ errorMessage }) => {
975
974
  const techdocsBuilder = useApi(configApiRef).getOptionalString("techdocs.builder");
976
975
  let additionalInfo = "";
977
976
  if (techdocsBuilder !== "local") {
@@ -1042,7 +1041,7 @@ const TechDocsStateIndicator = () => {
1042
1041
  action: /* @__PURE__ */ React.createElement(TechDocsBuildLogs, {
1043
1042
  buildLog
1044
1043
  }),
1045
- classes: {message: classes.message}
1044
+ classes: { message: classes.message }
1046
1045
  }, "Building a newer version of this documentation failed.", " ", syncErrorMessage);
1047
1046
  }
1048
1047
  if (state === "CONTENT_NOT_FOUND") {
@@ -1052,7 +1051,7 @@ const TechDocsStateIndicator = () => {
1052
1051
  action: /* @__PURE__ */ React.createElement(TechDocsBuildLogs, {
1053
1052
  buildLog
1054
1053
  }),
1055
- classes: {message: classes.message}
1054
+ classes: { message: classes.message }
1056
1055
  }, "Building a newer version of this documentation failed.", " ", syncErrorMessage), /* @__PURE__ */ React.createElement(TechDocsNotFound, {
1057
1056
  errorMessage: contentErrorMessage
1058
1057
  }));
@@ -1092,7 +1091,7 @@ function calculateDisplayState({
1092
1091
  return "CONTENT_FRESH";
1093
1092
  }
1094
1093
  function reducer(oldState, action) {
1095
- const newState = {...oldState};
1094
+ const newState = { ...oldState };
1096
1095
  switch (action.type) {
1097
1096
  case "sync":
1098
1097
  if (action.state === "CHECKING") {
@@ -1134,14 +1133,14 @@ function useReaderState(kind, namespace, name, path) {
1134
1133
  buildLog: []
1135
1134
  });
1136
1135
  const techdocsStorageApi = useApi(techdocsStorageApiRef);
1137
- const {retry: contentReload} = useAsyncRetry(async () => {
1138
- dispatch({type: "contentLoading"});
1136
+ const { retry: contentReload } = useAsyncRetry(async () => {
1137
+ dispatch({ type: "contentLoading" });
1139
1138
  try {
1140
- const entityDocs = await techdocsStorageApi.getEntityDocs({kind, namespace, name}, path);
1141
- dispatch({type: "content", content: entityDocs, path});
1139
+ const entityDocs = await techdocsStorageApi.getEntityDocs({ kind, namespace, name }, path);
1140
+ dispatch({ type: "content", content: entityDocs, path });
1142
1141
  return entityDocs;
1143
1142
  } catch (e) {
1144
- dispatch({type: "content", contentError: e, path});
1143
+ dispatch({ type: "content", contentError: e, path });
1145
1144
  }
1146
1145
  return void 0;
1147
1146
  }, [techdocsStorageApi, kind, namespace, name, path]);
@@ -1150,11 +1149,11 @@ function useReaderState(kind, namespace, name, path) {
1150
1149
  reload: () => {
1151
1150
  }
1152
1151
  });
1153
- contentRef.current = {content: state.content, reload: contentReload};
1152
+ contentRef.current = { content: state.content, reload: contentReload };
1154
1153
  useAsync(async () => {
1155
- dispatch({type: "sync", state: "CHECKING"});
1154
+ dispatch({ type: "sync", state: "CHECKING" });
1156
1155
  const buildingTimeout = setTimeout(() => {
1157
- dispatch({type: "sync", state: "BUILDING"});
1156
+ dispatch({ type: "sync", state: "BUILDING" });
1158
1157
  }, 1e3);
1159
1158
  try {
1160
1159
  const result = await techdocsStorageApi.syncEntityDocs({
@@ -1162,19 +1161,19 @@ function useReaderState(kind, namespace, name, path) {
1162
1161
  namespace,
1163
1162
  name
1164
1163
  }, (log) => {
1165
- dispatch({type: "buildLog", log});
1164
+ dispatch({ type: "buildLog", log });
1166
1165
  });
1167
1166
  switch (result) {
1168
1167
  case "updated":
1169
1168
  if (!contentRef.current.content) {
1170
1169
  contentRef.current.reload();
1171
- dispatch({type: "sync", state: "BUILD_READY_RELOAD"});
1170
+ dispatch({ type: "sync", state: "BUILD_READY_RELOAD" });
1172
1171
  } else {
1173
- dispatch({type: "sync", state: "BUILD_READY"});
1172
+ dispatch({ type: "sync", state: "BUILD_READY" });
1174
1173
  }
1175
1174
  break;
1176
1175
  case "cached":
1177
- dispatch({type: "sync", state: "UP_TO_DATE"});
1176
+ dispatch({ type: "sync", state: "UP_TO_DATE" });
1178
1177
  break;
1179
1178
  default:
1180
1179
  dispatch({
@@ -1185,7 +1184,7 @@ function useReaderState(kind, namespace, name, path) {
1185
1184
  break;
1186
1185
  }
1187
1186
  } catch (e) {
1188
- dispatch({type: "sync", state: "ERROR", syncError: e});
1187
+ dispatch({ type: "sync", state: "ERROR", syncError: e });
1189
1188
  } finally {
1190
1189
  clearTimeout(buildingTimeout);
1191
1190
  }
@@ -1218,24 +1217,30 @@ const useStyles = makeStyles((theme) => ({
1218
1217
  }
1219
1218
  }));
1220
1219
  const TechDocsReaderContext = createContext({});
1221
- const TechDocsReaderProvider = ({children}) => {
1222
- const {namespace = "", kind = "", name = "", "*": path} = useParams();
1220
+ const TechDocsReaderProvider = ({
1221
+ children,
1222
+ entityRef
1223
+ }) => {
1224
+ const { "*": path } = useParams();
1225
+ const { kind, namespace, name } = entityRef;
1223
1226
  const value = useReaderState(kind, namespace, name, path);
1224
1227
  return /* @__PURE__ */ React.createElement(TechDocsReaderContext.Provider, {
1225
1228
  value
1226
1229
  }, children);
1227
1230
  };
1228
- const withTechDocsReaderProvider = (Component) => (props) => /* @__PURE__ */ React.createElement(TechDocsReaderProvider, null, /* @__PURE__ */ React.createElement(Component, {
1231
+ const withTechDocsReaderProvider = (Component, entityRef) => (props) => /* @__PURE__ */ React.createElement(TechDocsReaderProvider, {
1232
+ entityRef
1233
+ }, /* @__PURE__ */ React.createElement(Component, {
1229
1234
  ...props
1230
1235
  }));
1231
1236
  const useTechDocsReader = () => useContext(TechDocsReaderContext);
1232
- const useTechDocsReaderDom = () => {
1237
+ const useTechDocsReaderDom = (entityRef) => {
1233
1238
  const navigate = useNavigate$1();
1234
1239
  const theme = useTheme();
1235
1240
  const techdocsStorageApi = useApi(techdocsStorageApiRef);
1236
1241
  const scmIntegrationsApi = useApi(scmIntegrationsApiRef);
1237
- const {namespace = "", kind = "", name = ""} = useParams();
1238
- const {state, path, content: rawPage} = useTechDocsReader();
1242
+ const { namespace = "", kind = "", name = "" } = entityRef;
1243
+ const { state, path, content: rawPage } = useTechDocsReader();
1239
1244
  const [sidebars, setSidebars] = useState();
1240
1245
  const [dom, setDom] = useState(null);
1241
1246
  const updateSidebarPosition = useCallback(() => {
@@ -1305,6 +1310,16 @@ const useTechDocsReaderDom = () => {
1305
1310
  .md-typeset .admonition, .md-typeset details {
1306
1311
  font-size: 1rem;
1307
1312
  }
1313
+
1314
+ /* style the checkmarks of the task list */
1315
+ .md-typeset .task-list-control .task-list-indicator::before {
1316
+ background-color: ${theme.palette.action.disabledBackground};
1317
+ }
1318
+ .md-typeset .task-list-control [type="checkbox"]:checked + .task-list-indicator:before {
1319
+ background-color: ${theme.palette.success.main};
1320
+ }
1321
+ /**/
1322
+
1308
1323
  @media screen and (max-width: 76.1875em) {
1309
1324
  .md-nav {
1310
1325
  background-color: ${theme.palette.background.default};
@@ -1371,8 +1386,8 @@ const useTechDocsReaderDom = () => {
1371
1386
  --md-details-icon: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M8.59 16.58L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.42z"/></svg>');
1372
1387
  }
1373
1388
  :host {
1374
- --md-tasklist-icon: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 2A10 10 0 002 12a10 10 0 0010 10 10 10 0 0010-10A10 10 0 0012 2z"/></svg>');
1375
- --md-tasklist-icon--checked: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2m-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg>');
1389
+ --md-tasklist-icon: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"/></svg>');
1390
+ --md-tasklist-icon--checked: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M19 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.11 0 2-.9 2-2V5c0-1.1-.89-2-2-2zm-9 14l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg>');
1376
1391
  }
1377
1392
  `
1378
1393
  })
@@ -1382,9 +1397,11 @@ const useTechDocsReaderDom = () => {
1382
1397
  namespace,
1383
1398
  scmIntegrationsApi,
1384
1399
  techdocsStorageApi,
1400
+ theme.palette.action.disabledBackground,
1385
1401
  theme.palette.background.default,
1386
1402
  theme.palette.background.paper,
1387
1403
  theme.palette.primary.main,
1404
+ theme.palette.success.main,
1388
1405
  theme.palette.text.primary,
1389
1406
  theme.typography.fontFamily
1390
1407
  ]);
@@ -1429,7 +1446,7 @@ const useTechDocsReaderDom = () => {
1429
1446
  if (!shouldReplaceContent) {
1430
1447
  return;
1431
1448
  }
1432
- window.scroll({top: 0});
1449
+ window.scroll({ top: 0 });
1433
1450
  const postTransformedDomElement = await postRender(preTransformedDomElement);
1434
1451
  setDom(postTransformedDomElement);
1435
1452
  });
@@ -1447,7 +1464,7 @@ const TheReader = ({
1447
1464
  }) => {
1448
1465
  var _a, _b;
1449
1466
  const classes = useStyles();
1450
- const dom = useTechDocsReaderDom();
1467
+ const dom = useTechDocsReaderDom(entityRef);
1451
1468
  const shadowDomRef = useRef(null);
1452
1469
  const onReadyRef = useRef(onReady);
1453
1470
  useEffect(() => {
@@ -1457,7 +1474,7 @@ const TheReader = ({
1457
1474
  if (!dom || !shadowDomRef.current)
1458
1475
  return;
1459
1476
  const shadowDiv = shadowDomRef.current;
1460
- const shadowRoot = shadowDiv.shadowRoot || shadowDiv.attachShadow({mode: "open"});
1477
+ const shadowRoot = shadowDiv.shadowRoot || shadowDiv.attachShadow({ mode: "open" });
1461
1478
  Array.from(shadowRoot.children).forEach((child) => shadowRoot.removeChild(child));
1462
1479
  shadowRoot.appendChild(dom);
1463
1480
  onReadyRef.current();
@@ -1477,7 +1494,9 @@ const Reader = ({
1477
1494
  onReady = () => {
1478
1495
  },
1479
1496
  withSearch = true
1480
- }) => /* @__PURE__ */ React.createElement(TechDocsReaderProvider, null, /* @__PURE__ */ React.createElement(TheReader, {
1497
+ }) => /* @__PURE__ */ React.createElement(TechDocsReaderProvider, {
1498
+ entityRef
1499
+ }, /* @__PURE__ */ React.createElement(TheReader, {
1481
1500
  entityRef,
1482
1501
  onReady,
1483
1502
  withSearch
@@ -1488,9 +1507,9 @@ const TechDocsPageHeader = ({
1488
1507
  entityMetadata,
1489
1508
  techDocsMetadata
1490
1509
  }) => {
1491
- const {name} = entityRef;
1492
- const {site_name: siteName, site_description: siteDescription} = techDocsMetadata || {};
1493
- const {locationMetadata, spec} = entityMetadata || {};
1510
+ const { name } = entityRef;
1511
+ const { site_name: siteName, site_description: siteDescription } = techDocsMetadata || {};
1512
+ const { locationMetadata, spec } = entityMetadata || {};
1494
1513
  const lifecycle = spec == null ? void 0 : spec.lifecycle;
1495
1514
  const ownedByRelations = entityMetadata ? getEntityRelations(entityMetadata, RELATION_OWNED_BY) : [];
1496
1515
  const docsRootLink = useRouteRef(rootRouteRef)();
@@ -1518,7 +1537,7 @@ const TechDocsPageHeader = ({
1518
1537
  target: "_blank",
1519
1538
  rel: "noopener noreferrer"
1520
1539
  }, /* @__PURE__ */ React.createElement(CodeIcon, {
1521
- style: {marginTop: "-25px", fill: "#fff"}
1540
+ style: { marginTop: "-25px", fill: "#fff" }
1522
1541
  }))
1523
1542
  }) : null);
1524
1543
  return /* @__PURE__ */ React.createElement(Header, {
@@ -1532,16 +1551,16 @@ const TechDocsPageHeader = ({
1532
1551
 
1533
1552
  const LegacyTechDocsPage = () => {
1534
1553
  const [documentReady, setDocumentReady] = useState(false);
1535
- const {namespace, kind, name} = useParams();
1554
+ const { namespace, kind, name } = useParams();
1536
1555
  const techdocsApi = useApi(techdocsApiRef);
1537
- const {value: techdocsMetadataValue} = useAsync(() => {
1556
+ const { value: techdocsMetadataValue } = useAsync(() => {
1538
1557
  if (documentReady) {
1539
- return techdocsApi.getTechDocsMetadata({kind, namespace, name});
1558
+ return techdocsApi.getTechDocsMetadata({ kind, namespace, name });
1540
1559
  }
1541
1560
  return Promise.resolve(void 0);
1542
1561
  }, [kind, namespace, name, techdocsApi, documentReady]);
1543
- const {value: entityMetadataValue, error: entityMetadataError} = useAsync(() => {
1544
- return techdocsApi.getEntityMetadata({kind, namespace, name});
1562
+ const { value: entityMetadataValue, error: entityMetadataError } = useAsync(() => {
1563
+ return techdocsApi.getEntityMetadata({ kind, namespace, name });
1545
1564
  }, [kind, namespace, name, techdocsApi]);
1546
1565
  const onReady = useCallback(() => {
1547
1566
  setDocumentReady(true);
@@ -1573,19 +1592,19 @@ const LegacyTechDocsPage = () => {
1573
1592
  })));
1574
1593
  };
1575
1594
 
1576
- const TechDocsPage = ({children}) => {
1595
+ const TechDocsPage = ({ children }) => {
1577
1596
  const outlet = useOutlet();
1578
1597
  const [documentReady, setDocumentReady] = useState(false);
1579
- const {namespace, kind, name} = useParams();
1598
+ const { namespace, kind, name } = useParams();
1580
1599
  const techdocsApi = useApi(techdocsApiRef);
1581
- const {value: techdocsMetadataValue} = useAsync(() => {
1600
+ const { value: techdocsMetadataValue } = useAsync(() => {
1582
1601
  if (documentReady) {
1583
- return techdocsApi.getTechDocsMetadata({kind, namespace, name});
1602
+ return techdocsApi.getTechDocsMetadata({ kind, namespace, name });
1584
1603
  }
1585
1604
  return Promise.resolve(void 0);
1586
1605
  }, [kind, namespace, name, techdocsApi, documentReady]);
1587
- const {value: entityMetadataValue, error: entityMetadataError} = useAsync(() => {
1588
- return techdocsApi.getEntityMetadata({kind, namespace, name});
1606
+ const { value: entityMetadataValue, error: entityMetadataError } = useAsync(() => {
1607
+ return techdocsApi.getEntityMetadata({ kind, namespace, name });
1589
1608
  }, [kind, namespace, name, techdocsApi]);
1590
1609
  const onReady = useCallback(() => {
1591
1610
  setDocumentReady(true);
@@ -1602,7 +1621,7 @@ const TechDocsPage = ({children}) => {
1602
1621
  }, children instanceof Function ? children({
1603
1622
  techdocsMetadataValue,
1604
1623
  entityMetadataValue,
1605
- entityRef: {kind, namespace, name},
1624
+ entityRef: { kind, namespace, name },
1606
1625
  onReady
1607
1626
  }) : children);
1608
1627
  };
@@ -1628,7 +1647,7 @@ const CustomPanel = ({
1628
1647
  }
1629
1648
  });
1630
1649
  const classes = useStyles();
1631
- const {value: user} = useOwnUser();
1650
+ const { value: user } = useOwnUser();
1632
1651
  const Panel = panels[config.panelType];
1633
1652
  const shownEntities = entities.filter((entity) => {
1634
1653
  if (config.filterPredicate === "ownedByUser") {
@@ -1693,7 +1712,7 @@ const TechDocsCustomHome = ({
1693
1712
  return /* @__PURE__ */ React.createElement(TechDocsPageWrapper, null, /* @__PURE__ */ React.createElement(HeaderTabs, {
1694
1713
  selectedIndex: selectedTab,
1695
1714
  onChange: (index) => setSelectedTab(index),
1696
- tabs: tabsConfig.map(({label}, index) => ({
1715
+ tabs: tabsConfig.map(({ label }, index) => ({
1697
1716
  id: index.toString(),
1698
1717
  label
1699
1718
  }))
@@ -1752,14 +1771,15 @@ var TechDocsIndexPage$1 = /*#__PURE__*/Object.freeze({
1752
1771
  TechDocsIndexPage: TechDocsIndexPage
1753
1772
  });
1754
1773
 
1755
- const EntityPageDocs = ({entity}) => {
1774
+ const EntityPageDocs = ({ entity }) => {
1756
1775
  var _a;
1776
+ const config = useApi(configApiRef);
1757
1777
  return /* @__PURE__ */ React.createElement(Reader, {
1758
1778
  withSearch: false,
1759
1779
  entityRef: {
1760
- kind: entity.kind,
1761
- namespace: (_a = entity.metadata.namespace) != null ? _a : "default",
1762
- name: entity.metadata.name
1780
+ namespace: toLowerMaybe((_a = entity.metadata.namespace) != null ? _a : "default", config),
1781
+ kind: toLowerMaybe(entity.kind, config),
1782
+ name: toLowerMaybe(entity.metadata.name, config)
1763
1783
  }
1764
1784
  });
1765
1785
  };
@@ -1780,7 +1800,7 @@ const Router = () => {
1780
1800
  };
1781
1801
  const EmbeddedDocsRouter = (_props) => {
1782
1802
  var _a;
1783
- const {entity} = useEntity();
1803
+ const { entity } = useEntity();
1784
1804
  const projectId = (_a = entity.metadata.annotations) == null ? void 0 : _a[TECHDOCS_ANNOTATION];
1785
1805
  if (!projectId) {
1786
1806
  return /* @__PURE__ */ React.createElement(MissingAnnotationEmptyState, {