@backstage/plugin-techdocs 0.12.7 → 0.12.11

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