@backstage/plugin-techdocs 0.12.8 → 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/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # @backstage/plugin-techdocs
2
2
 
3
+ ## 0.12.9
4
+
5
+ ### Patch Changes
6
+
7
+ - cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used.
8
+ - d90dad84b0: Switch to using `LogViewer` component from `@backstage/core-components` to display build logs.
9
+ - 3421826ca8: The problem of lowercase entity triplets which causes docs to not load on entity page is fixed.
10
+ - Updated dependencies
11
+ - @backstage/core-components@0.8.0
12
+ - @backstage/core-plugin-api@0.3.0
13
+ - @backstage/plugin-catalog@0.7.4
14
+ - @backstage/integration-react@0.1.15
15
+ - @backstage/plugin-catalog-react@0.6.5
16
+ - @backstage/plugin-search@0.5.1
17
+
3
18
  ## 0.12.8
4
19
 
5
20
  ### Patch Changes
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, {
@@ -228,10 +228,10 @@ function createCopyDocsUrlAction(copyToClipboard) {
228
228
  };
229
229
  }
230
230
  function createStarEntityAction(isStarredEntity, toggleStarredEntity) {
231
- return ({entity}) => {
231
+ return ({ entity }) => {
232
232
  const isStarred = isStarredEntity(entity);
233
233
  return {
234
- cellStyle: {paddingLeft: "1em"},
234
+ cellStyle: { paddingLeft: "1em" },
235
235
  icon: () => favoriteEntityIcon(isStarred),
236
236
  tooltip: favoriteEntityTooltip(isStarred),
237
237
  onClick: () => toggleStarredEntity(entity)
@@ -265,7 +265,7 @@ function createOwnerColumn() {
265
265
  return {
266
266
  title: "Owner",
267
267
  field: "resolved.ownedByRelationsTitle",
268
- render: ({resolved}) => /* @__PURE__ */ React.createElement(EntityRefLinks, {
268
+ render: ({ resolved }) => /* @__PURE__ */ React.createElement(EntityRefLinks, {
269
269
  entityRefs: resolved.ownedByRelations,
270
270
  defaultKind: "group"
271
271
  })
@@ -285,6 +285,10 @@ var columnFactories = /*#__PURE__*/Object.freeze({
285
285
  createTypeColumn: createTypeColumn
286
286
  });
287
287
 
288
+ function toLowerMaybe(str, config) {
289
+ return config.getOptionalBoolean("techdocs.legacyUseCaseSensitiveTripletPaths") ? str : str.toLocaleLowerCase("en-US");
290
+ }
291
+
288
292
  const DocsTable$1 = ({
289
293
  entities,
290
294
  title,
@@ -294,7 +298,7 @@ const DocsTable$1 = ({
294
298
  }) => {
295
299
  const [, copyToClipboard] = useCopyToClipboard();
296
300
  const getRouteToReaderPageFor = useRouteRef(rootDocsRouteRef);
297
- const toLowerMaybe = useApi(configApiRef).getOptionalBoolean("techdocs.legacyUseCaseSensitiveTripletPaths") ? (str) => str : (str) => str.toLocaleLowerCase("en-US");
301
+ const config = useApi(configApiRef);
298
302
  if (!entities)
299
303
  return null;
300
304
  const documents = entities.map((entity) => {
@@ -304,12 +308,12 @@ const DocsTable$1 = ({
304
308
  entity,
305
309
  resolved: {
306
310
  docsUrl: getRouteToReaderPageFor({
307
- namespace: toLowerMaybe((_a = entity.metadata.namespace) != null ? _a : "default"),
308
- kind: toLowerMaybe(entity.kind),
309
- 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)
310
314
  }),
311
315
  ownedByRelations,
312
- ownedByRelationsTitle: ownedByRelations.map((r) => formatEntityRefTitle(r, {defaultKind: "group"})).join(", ")
316
+ ownedByRelationsTitle: ownedByRelations.map((r) => formatEntityRefTitle(r, { defaultKind: "group" })).join(", ")
313
317
  }
314
318
  };
315
319
  });
@@ -355,8 +359,8 @@ const EntityListDocsTable = ({
355
359
  actions
356
360
  }) => {
357
361
  var _a, _b;
358
- const {loading, error, entities, filters} = useEntityListProvider();
359
- const {isStarredEntity, toggleStarredEntity} = useStarredEntities();
362
+ const { loading, error, entities, filters } = useEntityListProvider();
363
+ const { isStarredEntity, toggleStarredEntity } = useStarredEntities();
360
364
  const [, copyToClipboard] = useCopyToClipboard();
361
365
  const title = capitalize((_b = (_a = filters.user) == null ? void 0 : _a.value) != null ? _b : "all");
362
366
  const defaultActions = [
@@ -383,7 +387,7 @@ const EntityListDocsTable = ({
383
387
  EntityListDocsTable.columns = columnFactories;
384
388
  EntityListDocsTable.actions = actionFactories;
385
389
 
386
- const TechDocsPageWrapper = ({children}) => {
390
+ const TechDocsPageWrapper = ({ children }) => {
387
391
  var _a;
388
392
  const configApi = useApi(configApiRef);
389
393
  const generatedSubtitle = `Documentation available in ${(_a = configApi.getOptionalString("organization.name")) != null ? _a : "Backstage"}`;
@@ -402,7 +406,7 @@ class TechDocsFilter {
402
406
  }
403
407
  }
404
408
  const TechDocsPicker = () => {
405
- const {updateFilters} = useEntityListProvider();
409
+ const { updateFilters } = useEntityListProvider();
406
410
  useEffect(() => {
407
411
  updateFilters({
408
412
  techdocs: new TechDocsFilter()
@@ -430,7 +434,7 @@ const DocsCardGrid$1 = ({
430
434
  entities
431
435
  }) => {
432
436
  const getRouteToReaderPageFor = useRouteRef(rootDocsRouteRef);
433
- const toLowerMaybe = useApi(configApiRef).getOptionalBoolean("techdocs.legacyUseCaseSensitiveTripletPaths") ? (str) => str : (str) => str.toLocaleLowerCase("en-US");
437
+ const config = useApi(configApiRef);
434
438
  if (!entities)
435
439
  return null;
436
440
  return /* @__PURE__ */ React.createElement(ItemCardGrid, {
@@ -443,9 +447,9 @@ const DocsCardGrid$1 = ({
443
447
  title: (_a = entity.metadata.title) != null ? _a : entity.metadata.name
444
448
  })), /* @__PURE__ */ React.createElement(CardContent, null, entity.metadata.description), /* @__PURE__ */ React.createElement(CardActions, null, /* @__PURE__ */ React.createElement(Button, {
445
449
  to: getRouteToReaderPageFor({
446
- namespace: toLowerMaybe((_b = entity.metadata.namespace) != null ? _b : "default"),
447
- kind: toLowerMaybe(entity.kind),
448
- 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)
449
453
  }),
450
454
  color: "primary",
451
455
  "data-testid": "read_docs"
@@ -459,7 +463,7 @@ var DocsCardGrid$2 = /*#__PURE__*/Object.freeze({
459
463
  });
460
464
 
461
465
  const EntityListDocsGrid = () => {
462
- const {loading, error, entities} = useEntityListProvider();
466
+ const { loading, error, entities } = useEntityListProvider();
463
467
  if (error) {
464
468
  return /* @__PURE__ */ React.createElement(WarningPanel, {
465
469
  severity: "error",
@@ -491,7 +495,7 @@ const techdocsPlugin = createPlugin({
491
495
  discoveryApi: discoveryApiRef,
492
496
  identityApi: identityApiRef
493
497
  },
494
- factory: ({configApi, discoveryApi, identityApi}) => new TechDocsStorageClient({
498
+ factory: ({ configApi, discoveryApi, identityApi }) => new TechDocsStorageClient({
495
499
  configApi,
496
500
  discoveryApi,
497
501
  identityApi
@@ -504,7 +508,7 @@ const techdocsPlugin = createPlugin({
504
508
  discoveryApi: discoveryApiRef,
505
509
  identityApi: identityApiRef
506
510
  },
507
- factory: ({configApi, discoveryApi, identityApi}) => new TechDocsClient({
511
+ factory: ({ configApi, discoveryApi, identityApi }) => new TechDocsClient({
508
512
  configApi,
509
513
  discoveryApi,
510
514
  identityApi
@@ -577,7 +581,7 @@ const addBaseUrl = ({
577
581
  const newValue = await techdocsStorageApi.getBaseUrl(elemAttribute, entityId, path);
578
582
  if (isSvgNeedingInlining(attributeName, elemAttribute, apiOrigin)) {
579
583
  try {
580
- const svg = await fetch(newValue, {credentials: "include"});
584
+ const svg = await fetch(newValue, { credentials: "include" });
581
585
  const svgContent = await svg.text();
582
586
  elem.setAttribute(attributeName, `data:image/svg+xml;base64,${btoa(svgContent)}`);
583
587
  } catch (e) {
@@ -760,7 +764,7 @@ const sanitizeDOM = () => {
760
764
  };
761
765
  };
762
766
 
763
- const injectCss = ({css}) => {
767
+ const injectCss = ({ css }) => {
764
768
  return (dom) => {
765
769
  dom.getElementsByTagName("head")[0].insertAdjacentHTML("beforeend", `<style>${css}</style>`);
766
770
  return dom;
@@ -804,7 +808,7 @@ const TechDocsSearchBar = ({
804
808
  const {
805
809
  term,
806
810
  setTerm,
807
- result: {loading, value: searchVal}
811
+ result: { loading, value: searchVal }
808
812
  } = useSearch();
809
813
  const [options, setOptions] = useState([]);
810
814
  useEffect(() => {
@@ -827,7 +831,7 @@ const TechDocsSearchBar = ({
827
831
  };
828
832
  const handleSelection = (_, selection) => {
829
833
  if (selection == null ? void 0 : selection.document) {
830
- const {location} = selection.document;
834
+ const { location } = selection.document;
831
835
  navigate(location);
832
836
  }
833
837
  };
@@ -853,7 +857,7 @@ const TechDocsSearchBar = ({
853
857
  noOptionsText: "No results found",
854
858
  value: null,
855
859
  options,
856
- renderOption: ({document}) => /* @__PURE__ */ React.createElement(DocsResultListItem, {
860
+ renderOption: ({ document }) => /* @__PURE__ */ React.createElement(DocsResultListItem, {
857
861
  result: document,
858
862
  lineClamp: 3,
859
863
  asListItem: false,
@@ -899,7 +903,6 @@ const TechDocsSearch = (props) => {
899
903
  }));
900
904
  };
901
905
 
902
- const LazyLog = React.lazy(() => import('react-lazylog/build/LazyLog'));
903
906
  const useDrawerStyles = makeStyles((theme) => createStyles({
904
907
  paper: {
905
908
  width: "100%",
@@ -914,6 +917,9 @@ const useDrawerStyles = makeStyles((theme) => createStyles({
914
917
  root: {
915
918
  height: "100%",
916
919
  overflow: "hidden"
920
+ },
921
+ logs: {
922
+ background: theme.palette.background.default
917
923
  }
918
924
  }));
919
925
  const TechDocsBuildLogsDrawerContent = ({
@@ -921,6 +927,7 @@ const TechDocsBuildLogsDrawerContent = ({
921
927
  onClose
922
928
  }) => {
923
929
  const classes = useDrawerStyles();
930
+ const logText = buildLog.length === 0 ? "Waiting for logs..." : buildLog.join("\n");
924
931
  return /* @__PURE__ */ React.createElement(Grid, {
925
932
  container: true,
926
933
  direction: "column",
@@ -941,24 +948,19 @@ const TechDocsBuildLogsDrawerContent = ({
941
948
  title: "Close the drawer",
942
949
  onClick: onClose,
943
950
  color: "inherit"
944
- }, /* @__PURE__ */ React.createElement(Close, null))), /* @__PURE__ */ React.createElement(Suspense, {
945
- fallback: /* @__PURE__ */ React.createElement(Progress, null)
946
- }, /* @__PURE__ */ React.createElement(LazyLog, {
947
- text: buildLog.length === 0 ? "Waiting for logs..." : buildLog.join("\n"),
948
- extraLines: 1,
949
- follow: true,
950
- selectableLines: true,
951
- enableSearch: true
952
- })));
951
+ }, /* @__PURE__ */ React.createElement(Close, null))), /* @__PURE__ */ React.createElement(LogViewer, {
952
+ text: logText,
953
+ classes: { root: classes.logs }
954
+ }));
953
955
  };
954
- const TechDocsBuildLogs = ({buildLog}) => {
956
+ const TechDocsBuildLogs = ({ buildLog }) => {
955
957
  const classes = useDrawerStyles();
956
958
  const [open, setOpen] = useState(false);
957
959
  return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Button$1, {
958
960
  color: "inherit",
959
961
  onClick: () => setOpen(true)
960
962
  }, "Show Build Logs"), /* @__PURE__ */ React.createElement(Drawer, {
961
- classes: {paper: classes.paper},
963
+ classes: { paper: classes.paper },
962
964
  anchor: "right",
963
965
  open,
964
966
  onClose: () => setOpen(false)
@@ -968,7 +970,7 @@ const TechDocsBuildLogs = ({buildLog}) => {
968
970
  })));
969
971
  };
970
972
 
971
- const TechDocsNotFound = ({errorMessage}) => {
973
+ const TechDocsNotFound = ({ errorMessage }) => {
972
974
  const techdocsBuilder = useApi(configApiRef).getOptionalString("techdocs.builder");
973
975
  let additionalInfo = "";
974
976
  if (techdocsBuilder !== "local") {
@@ -1039,7 +1041,7 @@ const TechDocsStateIndicator = () => {
1039
1041
  action: /* @__PURE__ */ React.createElement(TechDocsBuildLogs, {
1040
1042
  buildLog
1041
1043
  }),
1042
- classes: {message: classes.message}
1044
+ classes: { message: classes.message }
1043
1045
  }, "Building a newer version of this documentation failed.", " ", syncErrorMessage);
1044
1046
  }
1045
1047
  if (state === "CONTENT_NOT_FOUND") {
@@ -1049,7 +1051,7 @@ const TechDocsStateIndicator = () => {
1049
1051
  action: /* @__PURE__ */ React.createElement(TechDocsBuildLogs, {
1050
1052
  buildLog
1051
1053
  }),
1052
- classes: {message: classes.message}
1054
+ classes: { message: classes.message }
1053
1055
  }, "Building a newer version of this documentation failed.", " ", syncErrorMessage), /* @__PURE__ */ React.createElement(TechDocsNotFound, {
1054
1056
  errorMessage: contentErrorMessage
1055
1057
  }));
@@ -1089,7 +1091,7 @@ function calculateDisplayState({
1089
1091
  return "CONTENT_FRESH";
1090
1092
  }
1091
1093
  function reducer(oldState, action) {
1092
- const newState = {...oldState};
1094
+ const newState = { ...oldState };
1093
1095
  switch (action.type) {
1094
1096
  case "sync":
1095
1097
  if (action.state === "CHECKING") {
@@ -1131,14 +1133,14 @@ function useReaderState(kind, namespace, name, path) {
1131
1133
  buildLog: []
1132
1134
  });
1133
1135
  const techdocsStorageApi = useApi(techdocsStorageApiRef);
1134
- const {retry: contentReload} = useAsyncRetry(async () => {
1135
- dispatch({type: "contentLoading"});
1136
+ const { retry: contentReload } = useAsyncRetry(async () => {
1137
+ dispatch({ type: "contentLoading" });
1136
1138
  try {
1137
- const entityDocs = await techdocsStorageApi.getEntityDocs({kind, namespace, name}, path);
1138
- dispatch({type: "content", content: entityDocs, path});
1139
+ const entityDocs = await techdocsStorageApi.getEntityDocs({ kind, namespace, name }, path);
1140
+ dispatch({ type: "content", content: entityDocs, path });
1139
1141
  return entityDocs;
1140
1142
  } catch (e) {
1141
- dispatch({type: "content", contentError: e, path});
1143
+ dispatch({ type: "content", contentError: e, path });
1142
1144
  }
1143
1145
  return void 0;
1144
1146
  }, [techdocsStorageApi, kind, namespace, name, path]);
@@ -1147,11 +1149,11 @@ function useReaderState(kind, namespace, name, path) {
1147
1149
  reload: () => {
1148
1150
  }
1149
1151
  });
1150
- contentRef.current = {content: state.content, reload: contentReload};
1152
+ contentRef.current = { content: state.content, reload: contentReload };
1151
1153
  useAsync(async () => {
1152
- dispatch({type: "sync", state: "CHECKING"});
1154
+ dispatch({ type: "sync", state: "CHECKING" });
1153
1155
  const buildingTimeout = setTimeout(() => {
1154
- dispatch({type: "sync", state: "BUILDING"});
1156
+ dispatch({ type: "sync", state: "BUILDING" });
1155
1157
  }, 1e3);
1156
1158
  try {
1157
1159
  const result = await techdocsStorageApi.syncEntityDocs({
@@ -1159,19 +1161,19 @@ function useReaderState(kind, namespace, name, path) {
1159
1161
  namespace,
1160
1162
  name
1161
1163
  }, (log) => {
1162
- dispatch({type: "buildLog", log});
1164
+ dispatch({ type: "buildLog", log });
1163
1165
  });
1164
1166
  switch (result) {
1165
1167
  case "updated":
1166
1168
  if (!contentRef.current.content) {
1167
1169
  contentRef.current.reload();
1168
- dispatch({type: "sync", state: "BUILD_READY_RELOAD"});
1170
+ dispatch({ type: "sync", state: "BUILD_READY_RELOAD" });
1169
1171
  } else {
1170
- dispatch({type: "sync", state: "BUILD_READY"});
1172
+ dispatch({ type: "sync", state: "BUILD_READY" });
1171
1173
  }
1172
1174
  break;
1173
1175
  case "cached":
1174
- dispatch({type: "sync", state: "UP_TO_DATE"});
1176
+ dispatch({ type: "sync", state: "UP_TO_DATE" });
1175
1177
  break;
1176
1178
  default:
1177
1179
  dispatch({
@@ -1182,7 +1184,7 @@ function useReaderState(kind, namespace, name, path) {
1182
1184
  break;
1183
1185
  }
1184
1186
  } catch (e) {
1185
- dispatch({type: "sync", state: "ERROR", syncError: e});
1187
+ dispatch({ type: "sync", state: "ERROR", syncError: e });
1186
1188
  } finally {
1187
1189
  clearTimeout(buildingTimeout);
1188
1190
  }
@@ -1219,8 +1221,8 @@ const TechDocsReaderProvider = ({
1219
1221
  children,
1220
1222
  entityRef
1221
1223
  }) => {
1222
- const {"*": path} = useParams();
1223
- const {kind, namespace, name} = entityRef;
1224
+ const { "*": path } = useParams();
1225
+ const { kind, namespace, name } = entityRef;
1224
1226
  const value = useReaderState(kind, namespace, name, path);
1225
1227
  return /* @__PURE__ */ React.createElement(TechDocsReaderContext.Provider, {
1226
1228
  value
@@ -1237,8 +1239,8 @@ const useTechDocsReaderDom = (entityRef) => {
1237
1239
  const theme = useTheme();
1238
1240
  const techdocsStorageApi = useApi(techdocsStorageApiRef);
1239
1241
  const scmIntegrationsApi = useApi(scmIntegrationsApiRef);
1240
- const {namespace = "", kind = "", name = ""} = entityRef;
1241
- const {state, path, content: rawPage} = useTechDocsReader();
1242
+ const { namespace = "", kind = "", name = "" } = entityRef;
1243
+ const { state, path, content: rawPage } = useTechDocsReader();
1242
1244
  const [sidebars, setSidebars] = useState();
1243
1245
  const [dom, setDom] = useState(null);
1244
1246
  const updateSidebarPosition = useCallback(() => {
@@ -1444,7 +1446,7 @@ const useTechDocsReaderDom = (entityRef) => {
1444
1446
  if (!shouldReplaceContent) {
1445
1447
  return;
1446
1448
  }
1447
- window.scroll({top: 0});
1449
+ window.scroll({ top: 0 });
1448
1450
  const postTransformedDomElement = await postRender(preTransformedDomElement);
1449
1451
  setDom(postTransformedDomElement);
1450
1452
  });
@@ -1472,7 +1474,7 @@ const TheReader = ({
1472
1474
  if (!dom || !shadowDomRef.current)
1473
1475
  return;
1474
1476
  const shadowDiv = shadowDomRef.current;
1475
- const shadowRoot = shadowDiv.shadowRoot || shadowDiv.attachShadow({mode: "open"});
1477
+ const shadowRoot = shadowDiv.shadowRoot || shadowDiv.attachShadow({ mode: "open" });
1476
1478
  Array.from(shadowRoot.children).forEach((child) => shadowRoot.removeChild(child));
1477
1479
  shadowRoot.appendChild(dom);
1478
1480
  onReadyRef.current();
@@ -1505,9 +1507,9 @@ const TechDocsPageHeader = ({
1505
1507
  entityMetadata,
1506
1508
  techDocsMetadata
1507
1509
  }) => {
1508
- const {name} = entityRef;
1509
- const {site_name: siteName, site_description: siteDescription} = techDocsMetadata || {};
1510
- const {locationMetadata, spec} = entityMetadata || {};
1510
+ const { name } = entityRef;
1511
+ const { site_name: siteName, site_description: siteDescription } = techDocsMetadata || {};
1512
+ const { locationMetadata, spec } = entityMetadata || {};
1511
1513
  const lifecycle = spec == null ? void 0 : spec.lifecycle;
1512
1514
  const ownedByRelations = entityMetadata ? getEntityRelations(entityMetadata, RELATION_OWNED_BY) : [];
1513
1515
  const docsRootLink = useRouteRef(rootRouteRef)();
@@ -1535,7 +1537,7 @@ const TechDocsPageHeader = ({
1535
1537
  target: "_blank",
1536
1538
  rel: "noopener noreferrer"
1537
1539
  }, /* @__PURE__ */ React.createElement(CodeIcon, {
1538
- style: {marginTop: "-25px", fill: "#fff"}
1540
+ style: { marginTop: "-25px", fill: "#fff" }
1539
1541
  }))
1540
1542
  }) : null);
1541
1543
  return /* @__PURE__ */ React.createElement(Header, {
@@ -1549,16 +1551,16 @@ const TechDocsPageHeader = ({
1549
1551
 
1550
1552
  const LegacyTechDocsPage = () => {
1551
1553
  const [documentReady, setDocumentReady] = useState(false);
1552
- const {namespace, kind, name} = useParams();
1554
+ const { namespace, kind, name } = useParams();
1553
1555
  const techdocsApi = useApi(techdocsApiRef);
1554
- const {value: techdocsMetadataValue} = useAsync(() => {
1556
+ const { value: techdocsMetadataValue } = useAsync(() => {
1555
1557
  if (documentReady) {
1556
- return techdocsApi.getTechDocsMetadata({kind, namespace, name});
1558
+ return techdocsApi.getTechDocsMetadata({ kind, namespace, name });
1557
1559
  }
1558
1560
  return Promise.resolve(void 0);
1559
1561
  }, [kind, namespace, name, techdocsApi, documentReady]);
1560
- const {value: entityMetadataValue, error: entityMetadataError} = useAsync(() => {
1561
- return techdocsApi.getEntityMetadata({kind, namespace, name});
1562
+ const { value: entityMetadataValue, error: entityMetadataError } = useAsync(() => {
1563
+ return techdocsApi.getEntityMetadata({ kind, namespace, name });
1562
1564
  }, [kind, namespace, name, techdocsApi]);
1563
1565
  const onReady = useCallback(() => {
1564
1566
  setDocumentReady(true);
@@ -1590,19 +1592,19 @@ const LegacyTechDocsPage = () => {
1590
1592
  })));
1591
1593
  };
1592
1594
 
1593
- const TechDocsPage = ({children}) => {
1595
+ const TechDocsPage = ({ children }) => {
1594
1596
  const outlet = useOutlet();
1595
1597
  const [documentReady, setDocumentReady] = useState(false);
1596
- const {namespace, kind, name} = useParams();
1598
+ const { namespace, kind, name } = useParams();
1597
1599
  const techdocsApi = useApi(techdocsApiRef);
1598
- const {value: techdocsMetadataValue} = useAsync(() => {
1600
+ const { value: techdocsMetadataValue } = useAsync(() => {
1599
1601
  if (documentReady) {
1600
- return techdocsApi.getTechDocsMetadata({kind, namespace, name});
1602
+ return techdocsApi.getTechDocsMetadata({ kind, namespace, name });
1601
1603
  }
1602
1604
  return Promise.resolve(void 0);
1603
1605
  }, [kind, namespace, name, techdocsApi, documentReady]);
1604
- const {value: entityMetadataValue, error: entityMetadataError} = useAsync(() => {
1605
- return techdocsApi.getEntityMetadata({kind, namespace, name});
1606
+ const { value: entityMetadataValue, error: entityMetadataError } = useAsync(() => {
1607
+ return techdocsApi.getEntityMetadata({ kind, namespace, name });
1606
1608
  }, [kind, namespace, name, techdocsApi]);
1607
1609
  const onReady = useCallback(() => {
1608
1610
  setDocumentReady(true);
@@ -1619,7 +1621,7 @@ const TechDocsPage = ({children}) => {
1619
1621
  }, children instanceof Function ? children({
1620
1622
  techdocsMetadataValue,
1621
1623
  entityMetadataValue,
1622
- entityRef: {kind, namespace, name},
1624
+ entityRef: { kind, namespace, name },
1623
1625
  onReady
1624
1626
  }) : children);
1625
1627
  };
@@ -1645,7 +1647,7 @@ const CustomPanel = ({
1645
1647
  }
1646
1648
  });
1647
1649
  const classes = useStyles();
1648
- const {value: user} = useOwnUser();
1650
+ const { value: user } = useOwnUser();
1649
1651
  const Panel = panels[config.panelType];
1650
1652
  const shownEntities = entities.filter((entity) => {
1651
1653
  if (config.filterPredicate === "ownedByUser") {
@@ -1710,7 +1712,7 @@ const TechDocsCustomHome = ({
1710
1712
  return /* @__PURE__ */ React.createElement(TechDocsPageWrapper, null, /* @__PURE__ */ React.createElement(HeaderTabs, {
1711
1713
  selectedIndex: selectedTab,
1712
1714
  onChange: (index) => setSelectedTab(index),
1713
- tabs: tabsConfig.map(({label}, index) => ({
1715
+ tabs: tabsConfig.map(({ label }, index) => ({
1714
1716
  id: index.toString(),
1715
1717
  label
1716
1718
  }))
@@ -1769,14 +1771,15 @@ var TechDocsIndexPage$1 = /*#__PURE__*/Object.freeze({
1769
1771
  TechDocsIndexPage: TechDocsIndexPage
1770
1772
  });
1771
1773
 
1772
- const EntityPageDocs = ({entity}) => {
1774
+ const EntityPageDocs = ({ entity }) => {
1773
1775
  var _a;
1776
+ const config = useApi(configApiRef);
1774
1777
  return /* @__PURE__ */ React.createElement(Reader, {
1775
1778
  withSearch: false,
1776
1779
  entityRef: {
1777
- kind: entity.kind,
1778
- namespace: (_a = entity.metadata.namespace) != null ? _a : "default",
1779
- 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)
1780
1783
  }
1781
1784
  });
1782
1785
  };
@@ -1797,7 +1800,7 @@ const Router = () => {
1797
1800
  };
1798
1801
  const EmbeddedDocsRouter = (_props) => {
1799
1802
  var _a;
1800
- const {entity} = useEntity();
1803
+ const { entity } = useEntity();
1801
1804
  const projectId = (_a = entity.metadata.annotations) == null ? void 0 : _a[TECHDOCS_ANNOTATION];
1802
1805
  if (!projectId) {
1803
1806
  return /* @__PURE__ */ React.createElement(MissingAnnotationEmptyState, {