@backstage/plugin-techdocs 0.12.6 → 0.12.10

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