@backstage/plugin-home 0.7.4 → 0.7.5-next.0
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 +17 -0
- package/alpha/package.json +1 -1
- package/dist/alpha.esm.js +9 -12
- package/dist/alpha.esm.js.map +1 -1
- package/dist/api/VisitsStorageApi.esm.js +13 -23
- package/dist/api/VisitsStorageApi.esm.js.map +1 -1
- package/dist/components/CustomHomepage/CustomHomepageGrid.esm.js +14 -19
- package/dist/components/CustomHomepage/CustomHomepageGrid.esm.js.map +1 -1
- package/dist/components/HomepageCompositionRoot.esm.js +1 -2
- package/dist/components/HomepageCompositionRoot.esm.js.map +1 -1
- package/dist/components/StarredEntityListItem/StarredEntityListItem.esm.js +1 -2
- package/dist/components/StarredEntityListItem/StarredEntityListItem.esm.js.map +1 -1
- package/dist/components/VisitList/ItemCategory.esm.js +2 -4
- package/dist/components/VisitList/ItemCategory.esm.js.map +1 -1
- package/dist/components/VisitList/ItemDetail.esm.js +1 -2
- package/dist/components/VisitList/ItemDetail.esm.js.map +1 -1
- package/dist/components/VisitListener.esm.js +5 -5
- package/dist/components/VisitListener.esm.js.map +1 -1
- package/dist/homePageComponents/FeaturedDocsCard/Content.esm.js +1 -1
- package/dist/homePageComponents/FeaturedDocsCard/Content.esm.js.map +1 -1
- package/dist/homePageComponents/HeaderWorldClock/HeaderWorldClock.esm.js +1 -1
- package/dist/homePageComponents/HeaderWorldClock/HeaderWorldClock.esm.js.map +1 -1
- package/dist/homePageComponents/StarredEntities/Content.esm.js +9 -16
- package/dist/homePageComponents/StarredEntities/Content.esm.js.map +1 -1
- package/dist/homePageComponents/Toolkit/Content.esm.js +1 -2
- package/dist/homePageComponents/Toolkit/Content.esm.js.map +1 -1
- package/dist/homePageComponents/VisitedByType/Content.esm.js +4 -5
- package/dist/homePageComponents/VisitedByType/Content.esm.js.map +1 -1
- package/dist/homePageComponents/WelcomeTitle/WelcomeTitle.esm.js +1 -1
- package/dist/homePageComponents/WelcomeTitle/WelcomeTitle.esm.js.map +1 -1
- package/package.json +10 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @backstage/plugin-home
|
|
2
2
|
|
|
3
|
+
## 0.7.5-next.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies
|
|
8
|
+
- @backstage/theme@0.5.6-next.0
|
|
9
|
+
- @backstage/core-components@0.14.8-next.0
|
|
10
|
+
- @backstage/catalog-client@1.6.5
|
|
11
|
+
- @backstage/catalog-model@1.5.0
|
|
12
|
+
- @backstage/config@1.2.0
|
|
13
|
+
- @backstage/core-app-api@1.12.5
|
|
14
|
+
- @backstage/core-compat-api@0.2.6-next.0
|
|
15
|
+
- @backstage/core-plugin-api@1.9.2
|
|
16
|
+
- @backstage/frontend-plugin-api@0.6.6-next.0
|
|
17
|
+
- @backstage/plugin-catalog-react@1.12.1-next.0
|
|
18
|
+
- @backstage/plugin-home-react@0.1.14-next.0
|
|
19
|
+
|
|
3
20
|
## 0.7.4
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
package/alpha/package.json
CHANGED
package/dist/alpha.esm.js
CHANGED
|
@@ -20,18 +20,15 @@ const homePage = createPageExtension({
|
|
|
20
20
|
)
|
|
21
21
|
},
|
|
22
22
|
loader: ({ inputs }) => import('./components/index.esm.js').then(
|
|
23
|
-
(m) =>
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
)
|
|
33
|
-
);
|
|
34
|
-
}
|
|
23
|
+
(m) => compatWrapper(
|
|
24
|
+
/* @__PURE__ */ React.createElement(
|
|
25
|
+
m.HomepageCompositionRoot,
|
|
26
|
+
{
|
|
27
|
+
children: inputs.props?.output.children,
|
|
28
|
+
title: inputs.props?.output.title
|
|
29
|
+
}
|
|
30
|
+
)
|
|
31
|
+
)
|
|
35
32
|
)
|
|
36
33
|
});
|
|
37
34
|
var alpha = createPlugin({
|
package/dist/alpha.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"alpha.esm.js","sources":["../src/alpha.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\n\nimport {\n coreExtensionData,\n createExtensionDataRef,\n createExtensionInput,\n createPageExtension,\n createPlugin,\n createRouteRef,\n} from '@backstage/frontend-plugin-api';\nimport { compatWrapper } from '@backstage/core-compat-api';\n\nconst rootRouteRef = createRouteRef();\n\n/**\n * @alpha\n */\nexport const titleExtensionDataRef = createExtensionDataRef<string>('title');\n\nconst homePage = createPageExtension({\n defaultPath: '/home',\n routeRef: rootRouteRef,\n inputs: {\n props: createExtensionInput(\n {\n children: coreExtensionData.reactElement.optional(),\n title: titleExtensionDataRef.optional(),\n },\n\n {\n singleton: true,\n optional: true,\n },\n ),\n },\n loader: ({ inputs }) =>\n import('./components/').then(m =>\n compatWrapper(\n <m.HomepageCompositionRoot\n children={inputs.props?.output.children}\n title={inputs.props?.output.title}\n />,\n ),\n ),\n});\n\n/**\n * @alpha\n */\nexport default createPlugin({\n id: 'home',\n extensions: [homePage],\n});\n"],"names":[],"mappings":";;;;AA4BA,MAAM,eAAe,cAAe,EAAA,CAAA;AAKvB,MAAA,qBAAA,GAAwB,uBAA+B,OAAO,EAAA;AAE3E,MAAM,WAAW,mBAAoB,CAAA;AAAA,EACnC,WAAa,EAAA,OAAA;AAAA,EACb,QAAU,EAAA,YAAA;AAAA,EACV,MAAQ,EAAA;AAAA,IACN,KAAO,EAAA,oBAAA;AAAA,MACL;AAAA,QACE,QAAA,EAAU,iBAAkB,CAAA,YAAA,CAAa,QAAS,EAAA;AAAA,QAClD,KAAA,EAAO,sBAAsB,QAAS,EAAA;AAAA,OACxC;AAAA,MAEA;AAAA,QACE,SAAW,EAAA,IAAA;AAAA,QACX,QAAU,EAAA,IAAA;AAAA,OACZ;AAAA,KACF;AAAA,GACF;AAAA,EACA,QAAQ,CAAC,EAAE,QACT,KAAA,OAAO,2BAAe,CAAE,CAAA,IAAA;AAAA,IAAK,
|
|
1
|
+
{"version":3,"file":"alpha.esm.js","sources":["../src/alpha.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\n\nimport {\n coreExtensionData,\n createExtensionDataRef,\n createExtensionInput,\n createPageExtension,\n createPlugin,\n createRouteRef,\n} from '@backstage/frontend-plugin-api';\nimport { compatWrapper } from '@backstage/core-compat-api';\n\nconst rootRouteRef = createRouteRef();\n\n/**\n * @alpha\n */\nexport const titleExtensionDataRef = createExtensionDataRef<string>('title');\n\nconst homePage = createPageExtension({\n defaultPath: '/home',\n routeRef: rootRouteRef,\n inputs: {\n props: createExtensionInput(\n {\n children: coreExtensionData.reactElement.optional(),\n title: titleExtensionDataRef.optional(),\n },\n\n {\n singleton: true,\n optional: true,\n },\n ),\n },\n loader: ({ inputs }) =>\n import('./components/').then(m =>\n compatWrapper(\n <m.HomepageCompositionRoot\n children={inputs.props?.output.children}\n title={inputs.props?.output.title}\n />,\n ),\n ),\n});\n\n/**\n * @alpha\n */\nexport default createPlugin({\n id: 'home',\n extensions: [homePage],\n});\n"],"names":[],"mappings":";;;;AA4BA,MAAM,eAAe,cAAe,EAAA,CAAA;AAKvB,MAAA,qBAAA,GAAwB,uBAA+B,OAAO,EAAA;AAE3E,MAAM,WAAW,mBAAoB,CAAA;AAAA,EACnC,WAAa,EAAA,OAAA;AAAA,EACb,QAAU,EAAA,YAAA;AAAA,EACV,MAAQ,EAAA;AAAA,IACN,KAAO,EAAA,oBAAA;AAAA,MACL;AAAA,QACE,QAAA,EAAU,iBAAkB,CAAA,YAAA,CAAa,QAAS,EAAA;AAAA,QAClD,KAAA,EAAO,sBAAsB,QAAS,EAAA;AAAA,OACxC;AAAA,MAEA;AAAA,QACE,SAAW,EAAA,IAAA;AAAA,QACX,QAAU,EAAA,IAAA;AAAA,OACZ;AAAA,KACF;AAAA,GACF;AAAA,EACA,QAAQ,CAAC,EAAE,QACT,KAAA,OAAO,2BAAe,CAAE,CAAA,IAAA;AAAA,IAAK,CAC3B,CAAA,KAAA,aAAA;AAAA,sBACE,KAAA,CAAA,aAAA;AAAA,QAAC,CAAE,CAAA,uBAAA;AAAA,QAAF;AAAA,UACC,QAAA,EAAU,MAAO,CAAA,KAAA,EAAO,MAAO,CAAA,QAAA;AAAA,UAC/B,KAAA,EAAO,MAAO,CAAA,KAAA,EAAO,MAAO,CAAA,KAAA;AAAA,SAAA;AAAA,OAC9B;AAAA,KACF;AAAA,GACF;AACJ,CAAC,CAAA,CAAA;AAKD,YAAe,YAAa,CAAA;AAAA,EAC1B,EAAI,EAAA,MAAA;AAAA,EACJ,UAAA,EAAY,CAAC,QAAQ,CAAA;AACvB,CAAC,CAAA;;;;"}
|
|
@@ -1,37 +1,29 @@
|
|
|
1
|
-
var __defProp = Object.defineProperty;
|
|
2
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
-
var __publicField = (obj, key, value) => {
|
|
4
|
-
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5
|
-
return value;
|
|
6
|
-
};
|
|
7
1
|
class VisitsStorageApi {
|
|
2
|
+
limit;
|
|
3
|
+
storageApi;
|
|
4
|
+
storageKeyPrefix = "@backstage/plugin-home:visits";
|
|
5
|
+
identityApi;
|
|
6
|
+
static create(options) {
|
|
7
|
+
return new VisitsStorageApi(options);
|
|
8
|
+
}
|
|
8
9
|
constructor(options) {
|
|
9
|
-
|
|
10
|
-
__publicField(this, "storageApi");
|
|
11
|
-
__publicField(this, "storageKeyPrefix", "@backstage/plugin-home:visits");
|
|
12
|
-
__publicField(this, "identityApi");
|
|
13
|
-
var _a;
|
|
14
|
-
this.limit = Math.abs((_a = options.limit) != null ? _a : 100);
|
|
10
|
+
this.limit = Math.abs(options.limit ?? 100);
|
|
15
11
|
this.storageApi = options.storageApi;
|
|
16
12
|
this.identityApi = options.identityApi;
|
|
17
13
|
}
|
|
18
|
-
static create(options) {
|
|
19
|
-
return new VisitsStorageApi(options);
|
|
20
|
-
}
|
|
21
14
|
/**
|
|
22
15
|
* Returns a list of visits through the visitsApi
|
|
23
16
|
*/
|
|
24
17
|
async list(queryParams) {
|
|
25
|
-
var _a, _b;
|
|
26
18
|
let visits = [...await this.retrieveAll()];
|
|
27
|
-
(
|
|
19
|
+
(queryParams?.orderBy ?? []).reverse().forEach((order) => {
|
|
28
20
|
if (order.direction === "asc") {
|
|
29
21
|
visits.sort((a, b) => this.compare(order, a, b));
|
|
30
22
|
} else {
|
|
31
23
|
visits.sort((a, b) => this.compare(order, b, a));
|
|
32
24
|
}
|
|
33
25
|
});
|
|
34
|
-
(
|
|
26
|
+
(queryParams?.filterBy ?? []).reverse().forEach((filter) => {
|
|
35
27
|
visits = visits.filter((visit) => {
|
|
36
28
|
const field = visit[filter.field];
|
|
37
29
|
if (filter.operator === ">")
|
|
@@ -81,17 +73,15 @@ class VisitsStorageApi {
|
|
|
81
73
|
return this.storageApi.set(storageKey, visits);
|
|
82
74
|
}
|
|
83
75
|
async retrieveAll() {
|
|
84
|
-
var _a;
|
|
85
76
|
const storageKey = await this.getStorageKey();
|
|
86
77
|
const snapshot = this.storageApi.snapshot(storageKey);
|
|
87
|
-
if (
|
|
88
|
-
return
|
|
78
|
+
if (snapshot?.presence !== "unknown") {
|
|
79
|
+
return snapshot?.value ?? [];
|
|
89
80
|
}
|
|
90
81
|
return new Promise((resolve, reject) => {
|
|
91
82
|
const subscription = this.storageApi.observe$(storageKey).subscribe({
|
|
92
83
|
next: (next) => {
|
|
93
|
-
|
|
94
|
-
const visits = (_a2 = next.value) != null ? _a2 : [];
|
|
84
|
+
const visits = next.value ?? [];
|
|
95
85
|
subscription.unsubscribe();
|
|
96
86
|
resolve(visits);
|
|
97
87
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VisitsStorageApi.esm.js","sources":["../../src/api/VisitsStorageApi.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { IdentityApi, StorageApi } from '@backstage/core-plugin-api';\nimport {\n Visit,\n VisitsApi,\n VisitsApiQueryParams,\n VisitsApiSaveParams,\n} from './VisitsApi';\n\n/** @public */\nexport type VisitsStorageApiOptions = {\n limit?: number;\n storageApi: StorageApi;\n identityApi: IdentityApi;\n};\n\ntype ArrayElement<A> = A extends readonly (infer T)[] ? T : never;\n\n/**\n * @public\n * This is an implementation of VisitsApi that relies on a StorageApi.\n * Beware that filtering and ordering are done in memory therefore it is\n * prudent to keep limit to a reasonable size.\n */\nexport class VisitsStorageApi implements VisitsApi {\n private readonly limit: number;\n private readonly storageApi: StorageApi;\n private readonly storageKeyPrefix = '@backstage/plugin-home:visits';\n private readonly identityApi: IdentityApi;\n\n static create(options: VisitsStorageApiOptions) {\n return new VisitsStorageApi(options);\n }\n\n private constructor(options: VisitsStorageApiOptions) {\n this.limit = Math.abs(options.limit ?? 100);\n this.storageApi = options.storageApi;\n this.identityApi = options.identityApi;\n }\n\n /**\n * Returns a list of visits through the visitsApi\n */\n async list(queryParams?: VisitsApiQueryParams): Promise<Visit[]> {\n let visits = [...(await this.retrieveAll())];\n\n // reversing order to guarantee orderBy priority\n (queryParams?.orderBy ?? []).reverse().forEach(order => {\n if (order.direction === 'asc') {\n visits.sort((a, b) => this.compare(order, a, b));\n } else {\n visits.sort((a, b) => this.compare(order, b, a));\n }\n });\n\n // reversing order to guarantee filterBy priority\n (queryParams?.filterBy ?? []).reverse().forEach(filter => {\n visits = visits.filter(visit => {\n const field = visit[filter.field] as number | string;\n if (filter.operator === '>') return field > filter.value;\n if (filter.operator === '>=') return field >= filter.value;\n if (filter.operator === '<') return field < filter.value;\n if (filter.operator === '<=') return field <= filter.value;\n if (filter.operator === '==') return field === filter.value;\n if (filter.operator === '!=') return field !== filter.value;\n if (filter.operator === 'contains')\n return `${field}`.includes(`${filter.value}`);\n return false;\n });\n });\n\n return visits;\n }\n\n /**\n * Saves a visit through the visitsApi\n */\n async save(saveParams: VisitsApiSaveParams): Promise<Visit> {\n const visits: Visit[] = [...(await this.retrieveAll())];\n\n const visit: Visit = {\n ...saveParams.visit,\n id: window.crypto.randomUUID(),\n hits: 1,\n timestamp: Date.now(),\n };\n\n // Updates entry if pathname is already registered\n const visitIndex = visits.findIndex(e => e.pathname === visit.pathname);\n if (visitIndex >= 0) {\n visit.id = visits[visitIndex].id;\n visit.hits = visits[visitIndex].hits + 1;\n visits[visitIndex] = visit;\n } else {\n visits.push(visit);\n }\n\n // Sort by time, most recent first\n visits.sort((a, b) => b.timestamp - a.timestamp);\n // Keep the most recent items up to limit\n await this.persistAll(visits.splice(0, this.limit));\n return visit;\n }\n\n private async persistAll(visits: Array<Visit>) {\n const storageKey = await this.getStorageKey();\n return this.storageApi.set<Array<Visit>>(storageKey, visits);\n }\n\n private async retrieveAll(): Promise<Array<Visit>> {\n const storageKey = await this.getStorageKey();\n // Handles for case when snapshot is and is not referenced per storaged type used\n const snapshot = this.storageApi.snapshot<Array<Visit>>(storageKey);\n if (snapshot?.presence !== 'unknown') {\n return snapshot?.value ?? [];\n }\n\n return new Promise((resolve, reject) => {\n const subscription = this.storageApi\n .observe$<Visit[]>(storageKey)\n .subscribe({\n next: next => {\n const visits = next.value ?? [];\n subscription.unsubscribe();\n resolve(visits);\n },\n error: err => {\n subscription.unsubscribe();\n reject(err);\n },\n });\n });\n }\n\n private async getStorageKey(): Promise<string> {\n const { userEntityRef } = await this.identityApi.getBackstageIdentity();\n const storageKey = `${this.storageKeyPrefix}:${userEntityRef}`;\n return storageKey;\n }\n\n // This assumes Visit fields are either numbers or strings\n private compare(\n order: ArrayElement<VisitsApiQueryParams['orderBy']>,\n a: Visit,\n b: Visit,\n ): number {\n const isNumber = typeof a[order.field] === 'number';\n return isNumber\n ? (a[order.field] as number) - (b[order.field] as number)\n : `${a[order.field]}`.localeCompare(`${b[order.field]}`);\n }\n}\n"],"names":["_a"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"VisitsStorageApi.esm.js","sources":["../../src/api/VisitsStorageApi.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { IdentityApi, StorageApi } from '@backstage/core-plugin-api';\nimport {\n Visit,\n VisitsApi,\n VisitsApiQueryParams,\n VisitsApiSaveParams,\n} from './VisitsApi';\n\n/** @public */\nexport type VisitsStorageApiOptions = {\n limit?: number;\n storageApi: StorageApi;\n identityApi: IdentityApi;\n};\n\ntype ArrayElement<A> = A extends readonly (infer T)[] ? T : never;\n\n/**\n * @public\n * This is an implementation of VisitsApi that relies on a StorageApi.\n * Beware that filtering and ordering are done in memory therefore it is\n * prudent to keep limit to a reasonable size.\n */\nexport class VisitsStorageApi implements VisitsApi {\n private readonly limit: number;\n private readonly storageApi: StorageApi;\n private readonly storageKeyPrefix = '@backstage/plugin-home:visits';\n private readonly identityApi: IdentityApi;\n\n static create(options: VisitsStorageApiOptions) {\n return new VisitsStorageApi(options);\n }\n\n private constructor(options: VisitsStorageApiOptions) {\n this.limit = Math.abs(options.limit ?? 100);\n this.storageApi = options.storageApi;\n this.identityApi = options.identityApi;\n }\n\n /**\n * Returns a list of visits through the visitsApi\n */\n async list(queryParams?: VisitsApiQueryParams): Promise<Visit[]> {\n let visits = [...(await this.retrieveAll())];\n\n // reversing order to guarantee orderBy priority\n (queryParams?.orderBy ?? []).reverse().forEach(order => {\n if (order.direction === 'asc') {\n visits.sort((a, b) => this.compare(order, a, b));\n } else {\n visits.sort((a, b) => this.compare(order, b, a));\n }\n });\n\n // reversing order to guarantee filterBy priority\n (queryParams?.filterBy ?? []).reverse().forEach(filter => {\n visits = visits.filter(visit => {\n const field = visit[filter.field] as number | string;\n if (filter.operator === '>') return field > filter.value;\n if (filter.operator === '>=') return field >= filter.value;\n if (filter.operator === '<') return field < filter.value;\n if (filter.operator === '<=') return field <= filter.value;\n if (filter.operator === '==') return field === filter.value;\n if (filter.operator === '!=') return field !== filter.value;\n if (filter.operator === 'contains')\n return `${field}`.includes(`${filter.value}`);\n return false;\n });\n });\n\n return visits;\n }\n\n /**\n * Saves a visit through the visitsApi\n */\n async save(saveParams: VisitsApiSaveParams): Promise<Visit> {\n const visits: Visit[] = [...(await this.retrieveAll())];\n\n const visit: Visit = {\n ...saveParams.visit,\n id: window.crypto.randomUUID(),\n hits: 1,\n timestamp: Date.now(),\n };\n\n // Updates entry if pathname is already registered\n const visitIndex = visits.findIndex(e => e.pathname === visit.pathname);\n if (visitIndex >= 0) {\n visit.id = visits[visitIndex].id;\n visit.hits = visits[visitIndex].hits + 1;\n visits[visitIndex] = visit;\n } else {\n visits.push(visit);\n }\n\n // Sort by time, most recent first\n visits.sort((a, b) => b.timestamp - a.timestamp);\n // Keep the most recent items up to limit\n await this.persistAll(visits.splice(0, this.limit));\n return visit;\n }\n\n private async persistAll(visits: Array<Visit>) {\n const storageKey = await this.getStorageKey();\n return this.storageApi.set<Array<Visit>>(storageKey, visits);\n }\n\n private async retrieveAll(): Promise<Array<Visit>> {\n const storageKey = await this.getStorageKey();\n // Handles for case when snapshot is and is not referenced per storaged type used\n const snapshot = this.storageApi.snapshot<Array<Visit>>(storageKey);\n if (snapshot?.presence !== 'unknown') {\n return snapshot?.value ?? [];\n }\n\n return new Promise((resolve, reject) => {\n const subscription = this.storageApi\n .observe$<Visit[]>(storageKey)\n .subscribe({\n next: next => {\n const visits = next.value ?? [];\n subscription.unsubscribe();\n resolve(visits);\n },\n error: err => {\n subscription.unsubscribe();\n reject(err);\n },\n });\n });\n }\n\n private async getStorageKey(): Promise<string> {\n const { userEntityRef } = await this.identityApi.getBackstageIdentity();\n const storageKey = `${this.storageKeyPrefix}:${userEntityRef}`;\n return storageKey;\n }\n\n // This assumes Visit fields are either numbers or strings\n private compare(\n order: ArrayElement<VisitsApiQueryParams['orderBy']>,\n a: Visit,\n b: Visit,\n ): number {\n const isNumber = typeof a[order.field] === 'number';\n return isNumber\n ? (a[order.field] as number) - (b[order.field] as number)\n : `${a[order.field]}`.localeCompare(`${b[order.field]}`);\n }\n}\n"],"names":[],"mappings":"AAsCO,MAAM,gBAAsC,CAAA;AAAA,EAChC,KAAA,CAAA;AAAA,EACA,UAAA,CAAA;AAAA,EACA,gBAAmB,GAAA,+BAAA,CAAA;AAAA,EACnB,WAAA,CAAA;AAAA,EAEjB,OAAO,OAAO,OAAkC,EAAA;AAC9C,IAAO,OAAA,IAAI,iBAAiB,OAAO,CAAA,CAAA;AAAA,GACrC;AAAA,EAEQ,YAAY,OAAkC,EAAA;AACpD,IAAA,IAAA,CAAK,KAAQ,GAAA,IAAA,CAAK,GAAI,CAAA,OAAA,CAAQ,SAAS,GAAG,CAAA,CAAA;AAC1C,IAAA,IAAA,CAAK,aAAa,OAAQ,CAAA,UAAA,CAAA;AAC1B,IAAA,IAAA,CAAK,cAAc,OAAQ,CAAA,WAAA,CAAA;AAAA,GAC7B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,KAAK,WAAsD,EAAA;AAC/D,IAAA,IAAI,SAAS,CAAC,GAAI,MAAM,IAAA,CAAK,aAAc,CAAA,CAAA;AAG3C,IAAA,CAAC,aAAa,OAAW,IAAA,IAAI,OAAQ,EAAA,CAAE,QAAQ,CAAS,KAAA,KAAA;AACtD,MAAI,IAAA,KAAA,CAAM,cAAc,KAAO,EAAA;AAC7B,QAAO,MAAA,CAAA,IAAA,CAAK,CAAC,CAAG,EAAA,CAAA,KAAM,KAAK,OAAQ,CAAA,KAAA,EAAO,CAAG,EAAA,CAAC,CAAC,CAAA,CAAA;AAAA,OAC1C,MAAA;AACL,QAAO,MAAA,CAAA,IAAA,CAAK,CAAC,CAAG,EAAA,CAAA,KAAM,KAAK,OAAQ,CAAA,KAAA,EAAO,CAAG,EAAA,CAAC,CAAC,CAAA,CAAA;AAAA,OACjD;AAAA,KACD,CAAA,CAAA;AAGD,IAAA,CAAC,aAAa,QAAY,IAAA,IAAI,OAAQ,EAAA,CAAE,QAAQ,CAAU,MAAA,KAAA;AACxD,MAAS,MAAA,GAAA,MAAA,CAAO,OAAO,CAAS,KAAA,KAAA;AAC9B,QAAM,MAAA,KAAA,GAAQ,KAAM,CAAA,MAAA,CAAO,KAAK,CAAA,CAAA;AAChC,QAAA,IAAI,OAAO,QAAa,KAAA,GAAA;AAAK,UAAA,OAAO,QAAQ,MAAO,CAAA,KAAA,CAAA;AACnD,QAAA,IAAI,OAAO,QAAa,KAAA,IAAA;AAAM,UAAA,OAAO,SAAS,MAAO,CAAA,KAAA,CAAA;AACrD,QAAA,IAAI,OAAO,QAAa,KAAA,GAAA;AAAK,UAAA,OAAO,QAAQ,MAAO,CAAA,KAAA,CAAA;AACnD,QAAA,IAAI,OAAO,QAAa,KAAA,IAAA;AAAM,UAAA,OAAO,SAAS,MAAO,CAAA,KAAA,CAAA;AACrD,QAAA,IAAI,OAAO,QAAa,KAAA,IAAA;AAAM,UAAA,OAAO,UAAU,MAAO,CAAA,KAAA,CAAA;AACtD,QAAA,IAAI,OAAO,QAAa,KAAA,IAAA;AAAM,UAAA,OAAO,UAAU,MAAO,CAAA,KAAA,CAAA;AACtD,QAAA,IAAI,OAAO,QAAa,KAAA,UAAA;AACtB,UAAA,OAAO,GAAG,KAAK,CAAA,CAAA,CAAG,SAAS,CAAG,EAAA,MAAA,CAAO,KAAK,CAAE,CAAA,CAAA,CAAA;AAC9C,QAAO,OAAA,KAAA,CAAA;AAAA,OACR,CAAA,CAAA;AAAA,KACF,CAAA,CAAA;AAED,IAAO,OAAA,MAAA,CAAA;AAAA,GACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,KAAK,UAAiD,EAAA;AAC1D,IAAA,MAAM,SAAkB,CAAC,GAAI,MAAM,IAAA,CAAK,aAAc,CAAA,CAAA;AAEtD,IAAA,MAAM,KAAe,GAAA;AAAA,MACnB,GAAG,UAAW,CAAA,KAAA;AAAA,MACd,EAAA,EAAI,MAAO,CAAA,MAAA,CAAO,UAAW,EAAA;AAAA,MAC7B,IAAM,EAAA,CAAA;AAAA,MACN,SAAA,EAAW,KAAK,GAAI,EAAA;AAAA,KACtB,CAAA;AAGA,IAAA,MAAM,aAAa,MAAO,CAAA,SAAA,CAAU,OAAK,CAAE,CAAA,QAAA,KAAa,MAAM,QAAQ,CAAA,CAAA;AACtE,IAAA,IAAI,cAAc,CAAG,EAAA;AACnB,MAAM,KAAA,CAAA,EAAA,GAAK,MAAO,CAAA,UAAU,CAAE,CAAA,EAAA,CAAA;AAC9B,MAAA,KAAA,CAAM,IAAO,GAAA,MAAA,CAAO,UAAU,CAAA,CAAE,IAAO,GAAA,CAAA,CAAA;AACvC,MAAA,MAAA,CAAO,UAAU,CAAI,GAAA,KAAA,CAAA;AAAA,KAChB,MAAA;AACL,MAAA,MAAA,CAAO,KAAK,KAAK,CAAA,CAAA;AAAA,KACnB;AAGA,IAAA,MAAA,CAAO,KAAK,CAAC,CAAA,EAAG,MAAM,CAAE,CAAA,SAAA,GAAY,EAAE,SAAS,CAAA,CAAA;AAE/C,IAAA,MAAM,KAAK,UAAW,CAAA,MAAA,CAAO,OAAO,CAAG,EAAA,IAAA,CAAK,KAAK,CAAC,CAAA,CAAA;AAClD,IAAO,OAAA,KAAA,CAAA;AAAA,GACT;AAAA,EAEA,MAAc,WAAW,MAAsB,EAAA;AAC7C,IAAM,MAAA,UAAA,GAAa,MAAM,IAAA,CAAK,aAAc,EAAA,CAAA;AAC5C,IAAA,OAAO,IAAK,CAAA,UAAA,CAAW,GAAkB,CAAA,UAAA,EAAY,MAAM,CAAA,CAAA;AAAA,GAC7D;AAAA,EAEA,MAAc,WAAqC,GAAA;AACjD,IAAM,MAAA,UAAA,GAAa,MAAM,IAAA,CAAK,aAAc,EAAA,CAAA;AAE5C,IAAA,MAAM,QAAW,GAAA,IAAA,CAAK,UAAW,CAAA,QAAA,CAAuB,UAAU,CAAA,CAAA;AAClE,IAAI,IAAA,QAAA,EAAU,aAAa,SAAW,EAAA;AACpC,MAAO,OAAA,QAAA,EAAU,SAAS,EAAC,CAAA;AAAA,KAC7B;AAEA,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAW,KAAA;AACtC,MAAA,MAAM,eAAe,IAAK,CAAA,UAAA,CACvB,QAAkB,CAAA,UAAU,EAC5B,SAAU,CAAA;AAAA,QACT,MAAM,CAAQ,IAAA,KAAA;AACZ,UAAM,MAAA,MAAA,GAAS,IAAK,CAAA,KAAA,IAAS,EAAC,CAAA;AAC9B,UAAA,YAAA,CAAa,WAAY,EAAA,CAAA;AACzB,UAAA,OAAA,CAAQ,MAAM,CAAA,CAAA;AAAA,SAChB;AAAA,QACA,OAAO,CAAO,GAAA,KAAA;AACZ,UAAA,YAAA,CAAa,WAAY,EAAA,CAAA;AACzB,UAAA,MAAA,CAAO,GAAG,CAAA,CAAA;AAAA,SACZ;AAAA,OACD,CAAA,CAAA;AAAA,KACJ,CAAA,CAAA;AAAA,GACH;AAAA,EAEA,MAAc,aAAiC,GAAA;AAC7C,IAAA,MAAM,EAAE,aAAc,EAAA,GAAI,MAAM,IAAA,CAAK,YAAY,oBAAqB,EAAA,CAAA;AACtE,IAAA,MAAM,UAAa,GAAA,CAAA,EAAG,IAAK,CAAA,gBAAgB,IAAI,aAAa,CAAA,CAAA,CAAA;AAC5D,IAAO,OAAA,UAAA,CAAA;AAAA,GACT;AAAA;AAAA,EAGQ,OAAA,CACN,KACA,EAAA,CAAA,EACA,CACQ,EAAA;AACR,IAAA,MAAM,QAAW,GAAA,OAAO,CAAE,CAAA,KAAA,CAAM,KAAK,CAAM,KAAA,QAAA,CAAA;AAC3C,IAAO,OAAA,QAAA,GACF,EAAE,KAAM,CAAA,KAAK,IAAgB,CAAE,CAAA,KAAA,CAAM,KAAK,CAC3C,GAAA,CAAA,EAAG,EAAE,KAAM,CAAA,KAAK,CAAC,CAAG,CAAA,CAAA,aAAA,CAAc,GAAG,CAAE,CAAA,KAAA,CAAM,KAAK,CAAC,CAAE,CAAA,CAAA,CAAA;AAAA,GAC3D;AACF;;;;"}
|
|
@@ -80,7 +80,6 @@ function useHomeStorage(defaultWidgets) {
|
|
|
80
80
|
}
|
|
81
81
|
const convertConfigToDefaultWidgets = (config, availableWidgets) => {
|
|
82
82
|
const ret = config.map((conf, i) => {
|
|
83
|
-
var _a, _b;
|
|
84
83
|
const c = LayoutConfigurationSchema.parse(conf);
|
|
85
84
|
const name = React.isValidElement(c.component) ? getComponentData(c.component, "core.extensionName") : c.component;
|
|
86
85
|
if (!name) {
|
|
@@ -97,8 +96,8 @@ const convertConfigToDefaultWidgets = (config, availableWidgets) => {
|
|
|
97
96
|
i: widgetId,
|
|
98
97
|
x: c.x,
|
|
99
98
|
y: c.y,
|
|
100
|
-
w: Math.min(
|
|
101
|
-
h: Math.min(
|
|
99
|
+
w: Math.min(widget.maxWidth ?? Number.MAX_VALUE, c.width),
|
|
100
|
+
h: Math.min(widget.maxHeight ?? Number.MAX_VALUE, c.height),
|
|
102
101
|
minW: widget.minWidth,
|
|
103
102
|
maxW: widget.maxWidth,
|
|
104
103
|
minH: widget.minHeight,
|
|
@@ -118,7 +117,6 @@ const availableWidgetsFilter = (elements) => {
|
|
|
118
117
|
return elements.selectByComponentData({
|
|
119
118
|
key: "core.extensionName"
|
|
120
119
|
}).getElements().flatMap((elem) => {
|
|
121
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
|
|
122
120
|
const config = getComponentData(elem, "home.widget.config");
|
|
123
121
|
return [
|
|
124
122
|
WidgetSchema.parse({
|
|
@@ -126,20 +124,19 @@ const availableWidgetsFilter = (elements) => {
|
|
|
126
124
|
name: getComponentData(elem, "core.extensionName"),
|
|
127
125
|
title: getComponentData(elem, "title"),
|
|
128
126
|
description: getComponentData(elem, "description"),
|
|
129
|
-
settingsSchema:
|
|
130
|
-
uiSchema:
|
|
131
|
-
width:
|
|
132
|
-
minWidth:
|
|
133
|
-
maxWidth:
|
|
134
|
-
height:
|
|
135
|
-
minHeight:
|
|
136
|
-
maxHeight:
|
|
127
|
+
settingsSchema: config?.settings?.schema,
|
|
128
|
+
uiSchema: config?.settings?.uiSchema,
|
|
129
|
+
width: config?.layout?.width?.defaultColumns,
|
|
130
|
+
minWidth: config?.layout?.width?.minColumns,
|
|
131
|
+
maxWidth: config?.layout?.width?.maxColumns,
|
|
132
|
+
height: config?.layout?.height?.defaultRows,
|
|
133
|
+
minHeight: config?.layout?.height?.minRows,
|
|
134
|
+
maxHeight: config?.layout?.height?.maxRows
|
|
137
135
|
})
|
|
138
136
|
];
|
|
139
137
|
});
|
|
140
138
|
};
|
|
141
139
|
const CustomHomepageGrid = (props) => {
|
|
142
|
-
var _a;
|
|
143
140
|
const styles = useStyles();
|
|
144
141
|
const theme = useTheme();
|
|
145
142
|
const availableWidgets = useElementFilter(
|
|
@@ -161,7 +158,6 @@ const CustomHomepageGrid = (props) => {
|
|
|
161
158
|
return key.split("__")[0];
|
|
162
159
|
};
|
|
163
160
|
const handleAdd = (widget) => {
|
|
164
|
-
var _a2, _b, _c, _d;
|
|
165
161
|
const widgetId = `${widget.name}__${widgets.length + 1}${Math.random().toString(36).slice(2)}`;
|
|
166
162
|
setWidgets([
|
|
167
163
|
...widgets,
|
|
@@ -171,8 +167,8 @@ const CustomHomepageGrid = (props) => {
|
|
|
171
167
|
i: widgetId,
|
|
172
168
|
x: 0,
|
|
173
169
|
y: Math.max(...widgets.map((w) => w.layout.y + w.layout.h)) + 1,
|
|
174
|
-
w: Math.min(
|
|
175
|
-
h: Math.min(
|
|
170
|
+
w: Math.min(widget.maxWidth ?? Number.MAX_VALUE, widget.width ?? 12),
|
|
171
|
+
h: Math.min(widget.maxHeight ?? Number.MAX_VALUE, widget.height ?? 4),
|
|
176
172
|
minW: widget.minWidth,
|
|
177
173
|
maxW: widget.maxWidth,
|
|
178
174
|
minH: widget.minHeight,
|
|
@@ -276,12 +272,11 @@ const CustomHomepageGrid = (props) => {
|
|
|
276
272
|
margin: props.containerMargin,
|
|
277
273
|
breakpoints: props.breakpoints ? props.breakpoints : theme.breakpoints.values,
|
|
278
274
|
cols: props.cols ? props.cols : { xl: 12, lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 },
|
|
279
|
-
rowHeight:
|
|
275
|
+
rowHeight: props.rowHeight ?? 60,
|
|
280
276
|
onLayoutChange: handleLayoutChange,
|
|
281
277
|
layouts: { xl: widgets.map((w) => w.layout) }
|
|
282
278
|
},
|
|
283
279
|
widgets.map((w) => {
|
|
284
|
-
var _a2;
|
|
285
280
|
const l = w.layout;
|
|
286
281
|
const widgetName = getWidgetNameFromKey(l.i);
|
|
287
282
|
const widget = getWidgetByName(widgetName);
|
|
@@ -290,7 +285,7 @@ const CustomHomepageGrid = (props) => {
|
|
|
290
285
|
}
|
|
291
286
|
const widgetProps = {
|
|
292
287
|
...widget.component.props,
|
|
293
|
-
...
|
|
288
|
+
...w.settings ?? {}
|
|
294
289
|
};
|
|
295
290
|
return /* @__PURE__ */ React.createElement(
|
|
296
291
|
"div",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CustomHomepageGrid.esm.js","sources":["../../../src/components/CustomHomepage/CustomHomepageGrid.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useCallback, useMemo } from 'react';\nimport { Layout, Layouts, Responsive, WidthProvider } from 'react-grid-layout';\nimport {\n ElementCollection,\n getComponentData,\n storageApiRef,\n useApi,\n useElementFilter,\n} from '@backstage/core-plugin-api';\nimport 'react-grid-layout/css/styles.css';\nimport 'react-resizable/css/styles.css';\nimport Dialog from '@material-ui/core/Dialog';\nimport {\n createStyles,\n makeStyles,\n Theme,\n useTheme,\n} from '@material-ui/core/styles';\nimport { compact } from 'lodash';\nimport useObservable from 'react-use/esm/useObservable';\nimport { ContentHeader, ErrorBoundary } from '@backstage/core-components';\nimport Typography from '@material-ui/core/Typography';\nimport { WidgetSettingsOverlay } from './WidgetSettingsOverlay';\nimport { AddWidgetDialog } from './AddWidgetDialog';\nimport { CustomHomepageButtons } from './CustomHomepageButtons';\nimport {\n CustomHomepageGridProps,\n CustomHomepageGridStateV1,\n CustomHomepageGridStateV1Schema,\n GridWidget,\n LayoutConfiguration,\n LayoutConfigurationSchema,\n Widget,\n WidgetSchema,\n} from './types';\nimport { CardConfig } from '@backstage/plugin-home-react';\n\n// eslint-disable-next-line new-cap\nconst ResponsiveGrid = WidthProvider(Responsive);\n\nconst useStyles = makeStyles((theme: Theme) =>\n createStyles({\n responsiveGrid: {\n '& .react-grid-item > .react-resizable-handle:after': {\n position: 'absolute',\n content: '\"\"',\n borderStyle: 'solid',\n borderWidth: '0 0 20px 20px',\n borderColor: `transparent transparent ${theme.palette.primary.light} transparent`,\n },\n },\n contentHeaderBtn: {\n marginLeft: theme.spacing(2),\n },\n widgetWrapper: {\n '& > div[class*=\"MuiCard-root\"]': {\n width: '100%',\n height: '100%',\n },\n '& div[class*=\"MuiCardContent-root\"]': {\n overflow: 'auto',\n },\n '& + .react-grid-placeholder': {\n backgroundColor: theme.palette.primary.light,\n },\n '&.edit > :active': {\n cursor: 'move',\n },\n },\n }),\n);\n\nfunction useHomeStorage(\n defaultWidgets: GridWidget[],\n): [GridWidget[], (value: GridWidget[]) => void] {\n const key = 'home';\n const storageApi = useApi(storageApiRef).forBucket('home.customHomepage');\n // TODO: Support multiple home pages\n const setWidgets = useCallback(\n (value: GridWidget[]) => {\n const grid: CustomHomepageGridStateV1 = {\n version: 1,\n pages: {\n default: value,\n },\n };\n storageApi.set(key, JSON.stringify(grid));\n },\n [key, storageApi],\n );\n const homeSnapshot = useObservable(\n storageApi.observe$<string>(key),\n storageApi.snapshot(key),\n );\n const widgets: GridWidget[] = useMemo(() => {\n if (homeSnapshot.presence === 'absent') {\n return defaultWidgets;\n }\n try {\n const grid: CustomHomepageGridStateV1 = JSON.parse(homeSnapshot.value!);\n return CustomHomepageGridStateV1Schema.parse(grid).pages.default;\n } catch (e) {\n return defaultWidgets;\n }\n }, [homeSnapshot, defaultWidgets]);\n\n return [widgets, setWidgets];\n}\n\nconst convertConfigToDefaultWidgets = (\n config: LayoutConfiguration[],\n availableWidgets: Widget[],\n): GridWidget[] => {\n const ret = config.map((conf, i) => {\n const c = LayoutConfigurationSchema.parse(conf);\n const name = React.isValidElement(c.component)\n ? getComponentData(c.component, 'core.extensionName')\n : (c.component as unknown as string);\n if (!name) {\n return null;\n }\n const widget = availableWidgets.find(w => w.name === name);\n if (!widget) {\n return null;\n }\n const widgetId = `${widget.name}__${i}${Math.random()\n .toString(36)\n .slice(2)}`;\n return {\n id: widgetId,\n layout: {\n i: widgetId,\n x: c.x,\n y: c.y,\n w: Math.min(widget.maxWidth ?? Number.MAX_VALUE, c.width),\n h: Math.min(widget.maxHeight ?? Number.MAX_VALUE, c.height),\n minW: widget.minWidth,\n maxW: widget.maxWidth,\n minH: widget.minHeight,\n maxH: widget.maxHeight,\n isDraggable: false,\n isResizable: false,\n },\n settings: {},\n movable: conf.movable,\n deletable: conf.deletable,\n resizable: conf.resizable,\n };\n });\n return compact(ret);\n};\n\nconst availableWidgetsFilter = (elements: ElementCollection) => {\n return elements\n .selectByComponentData({\n key: 'core.extensionName',\n })\n .getElements<Widget>()\n .flatMap(elem => {\n const config = getComponentData<CardConfig>(elem, 'home.widget.config');\n return [\n WidgetSchema.parse({\n component: elem,\n name: getComponentData<string>(elem, 'core.extensionName'),\n title: getComponentData<string>(elem, 'title'),\n description: getComponentData<string>(elem, 'description'),\n settingsSchema: config?.settings?.schema,\n uiSchema: config?.settings?.uiSchema,\n width: config?.layout?.width?.defaultColumns,\n minWidth: config?.layout?.width?.minColumns,\n maxWidth: config?.layout?.width?.maxColumns,\n height: config?.layout?.height?.defaultRows,\n minHeight: config?.layout?.height?.minRows,\n maxHeight: config?.layout?.height?.maxRows,\n }),\n ];\n });\n};\n\n/**\n * A component that allows customizing components in home grid layout.\n *\n * @public\n */\nexport const CustomHomepageGrid = (props: CustomHomepageGridProps) => {\n const styles = useStyles();\n const theme = useTheme();\n const availableWidgets = useElementFilter(\n props.children,\n availableWidgetsFilter,\n [props],\n );\n const defaultLayout = useMemo(() => {\n return props.config\n ? convertConfigToDefaultWidgets(props.config, availableWidgets)\n : [];\n }, [props.config, availableWidgets]);\n const [widgets, setWidgets] = useHomeStorage(defaultLayout);\n const [addWidgetDialogOpen, setAddWidgetDialogOpen] = React.useState(false);\n const editModeOn = widgets.find(w => w.layout.isResizable) !== undefined;\n const [editMode, setEditMode] = React.useState(editModeOn);\n const getWidgetByName = (name: string) => {\n return availableWidgets.find(widget => widget.name === name);\n };\n\n const getWidgetNameFromKey = (key: string) => {\n return key.split('__')[0];\n };\n\n const handleAdd = (widget: Widget) => {\n const widgetId = `${widget.name}__${widgets.length + 1}${Math.random()\n .toString(36)\n .slice(2)}`;\n\n setWidgets([\n ...widgets,\n {\n id: widgetId,\n layout: {\n i: widgetId,\n x: 0,\n y: Math.max(...widgets.map(w => w.layout.y + w.layout.h)) + 1,\n w: Math.min(widget.maxWidth ?? Number.MAX_VALUE, widget.width ?? 12),\n h: Math.min(widget.maxHeight ?? Number.MAX_VALUE, widget.height ?? 4),\n minW: widget.minWidth,\n maxW: widget.maxWidth,\n minH: widget.minHeight,\n maxH: widget.maxHeight,\n isResizable: editMode,\n isDraggable: editMode,\n },\n settings: {},\n movable: widget.movable,\n deletable: widget.deletable,\n resizable: widget.resizable,\n },\n ]);\n setAddWidgetDialogOpen(false);\n };\n\n const handleRemove = (widgetId: string) => {\n setWidgets(widgets.filter(w => w.id !== widgetId));\n };\n\n const handleSettingsSave = (\n widgetId: string,\n widgetSettings: Record<string, any>,\n ) => {\n const idx = widgets.findIndex(w => w.id === widgetId);\n if (idx >= 0) {\n const widget = widgets[idx];\n widget.settings = widgetSettings;\n widgets[idx] = widget;\n setWidgets(widgets);\n }\n };\n\n const clearLayout = () => {\n setWidgets([]);\n };\n\n const changeEditMode = (mode: boolean) => {\n setEditMode(mode);\n setWidgets(\n widgets.map(w => {\n const resizable = w.resizable === false ? false : mode;\n const movable = w.movable === false ? false : mode;\n return {\n ...w,\n layout: { ...w.layout, isDraggable: movable, isResizable: resizable },\n };\n }),\n );\n };\n\n const handleLayoutChange = (newLayout: Layout[], _: Layouts) => {\n if (editMode) {\n const newWidgets = newLayout.map(l => {\n const widget = widgets.find(w => w.id === l.i);\n return {\n ...widget,\n layout: l,\n } as GridWidget;\n });\n setWidgets(newWidgets);\n }\n };\n\n const handleRestoreDefaultConfig = () => {\n setWidgets(\n defaultLayout.map(w => {\n const resizable = w.resizable === false ? false : editMode;\n const movable = w.movable === false ? false : editMode;\n return {\n ...w,\n layout: {\n ...w.layout,\n isDraggable: movable,\n isResizable: resizable,\n },\n };\n }),\n );\n };\n\n return (\n <>\n <ContentHeader title=\"\">\n <CustomHomepageButtons\n editMode={editMode}\n numWidgets={widgets.length}\n clearLayout={clearLayout}\n setAddWidgetDialogOpen={setAddWidgetDialogOpen}\n changeEditMode={changeEditMode}\n defaultConfigAvailable={props.config !== undefined}\n restoreDefault={handleRestoreDefaultConfig}\n />\n </ContentHeader>\n <Dialog\n open={addWidgetDialogOpen}\n onClose={() => setAddWidgetDialogOpen(false)}\n >\n <AddWidgetDialog widgets={availableWidgets} handleAdd={handleAdd} />\n </Dialog>\n {!editMode && widgets.length === 0 && (\n <Typography variant=\"h5\" align=\"center\">\n No widgets added. Start by clicking the 'Add widget' button.\n </Typography>\n )}\n <ResponsiveGrid\n className={styles.responsiveGrid}\n measureBeforeMount\n compactType={props.compactType}\n style={props.style}\n allowOverlap={props.allowOverlap}\n preventCollision={props.preventCollision}\n draggableCancel=\".overlayGridItem,.widgetSettingsDialog,.disabled\"\n containerPadding={props.containerPadding}\n margin={props.containerMargin}\n breakpoints={\n props.breakpoints ? props.breakpoints : theme.breakpoints.values\n }\n cols={\n props.cols\n ? props.cols\n : { xl: 12, lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 }\n }\n rowHeight={props.rowHeight ?? 60}\n onLayoutChange={handleLayoutChange}\n layouts={{ xl: widgets.map(w => w.layout) }}\n >\n {widgets.map((w: GridWidget) => {\n const l = w.layout;\n const widgetName = getWidgetNameFromKey(l.i);\n const widget = getWidgetByName(widgetName);\n if (!widget || !widget.component) {\n return null;\n }\n\n const widgetProps = {\n ...widget.component.props,\n ...(w.settings ?? {}),\n };\n\n return (\n <div\n key={l.i}\n className={`${styles.widgetWrapper} ${editMode && 'edit'} ${\n w.movable === false && 'disabled'\n }`}\n >\n <ErrorBoundary>\n <widget.component.type {...widgetProps} />\n </ErrorBoundary>\n {editMode && (\n <WidgetSettingsOverlay\n id={l.i}\n widget={widget}\n handleRemove={handleRemove}\n handleSettingsSave={handleSettingsSave}\n settings={w.settings}\n deletable={w.deletable}\n />\n )}\n </div>\n );\n })}\n </ResponsiveGrid>\n </>\n );\n};\n"],"names":["_a"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CustomHomepageGrid.esm.js","sources":["../../../src/components/CustomHomepage/CustomHomepageGrid.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useCallback, useMemo } from 'react';\nimport { Layout, Layouts, Responsive, WidthProvider } from 'react-grid-layout';\nimport {\n ElementCollection,\n getComponentData,\n storageApiRef,\n useApi,\n useElementFilter,\n} from '@backstage/core-plugin-api';\nimport 'react-grid-layout/css/styles.css';\nimport 'react-resizable/css/styles.css';\nimport Dialog from '@material-ui/core/Dialog';\nimport {\n createStyles,\n makeStyles,\n Theme,\n useTheme,\n} from '@material-ui/core/styles';\nimport { compact } from 'lodash';\nimport useObservable from 'react-use/esm/useObservable';\nimport { ContentHeader, ErrorBoundary } from '@backstage/core-components';\nimport Typography from '@material-ui/core/Typography';\nimport { WidgetSettingsOverlay } from './WidgetSettingsOverlay';\nimport { AddWidgetDialog } from './AddWidgetDialog';\nimport { CustomHomepageButtons } from './CustomHomepageButtons';\nimport {\n CustomHomepageGridProps,\n CustomHomepageGridStateV1,\n CustomHomepageGridStateV1Schema,\n GridWidget,\n LayoutConfiguration,\n LayoutConfigurationSchema,\n Widget,\n WidgetSchema,\n} from './types';\nimport { CardConfig } from '@backstage/plugin-home-react';\n\n// eslint-disable-next-line new-cap\nconst ResponsiveGrid = WidthProvider(Responsive);\n\nconst useStyles = makeStyles((theme: Theme) =>\n createStyles({\n responsiveGrid: {\n '& .react-grid-item > .react-resizable-handle:after': {\n position: 'absolute',\n content: '\"\"',\n borderStyle: 'solid',\n borderWidth: '0 0 20px 20px',\n borderColor: `transparent transparent ${theme.palette.primary.light} transparent`,\n },\n },\n contentHeaderBtn: {\n marginLeft: theme.spacing(2),\n },\n widgetWrapper: {\n '& > div[class*=\"MuiCard-root\"]': {\n width: '100%',\n height: '100%',\n },\n '& div[class*=\"MuiCardContent-root\"]': {\n overflow: 'auto',\n },\n '& + .react-grid-placeholder': {\n backgroundColor: theme.palette.primary.light,\n },\n '&.edit > :active': {\n cursor: 'move',\n },\n },\n }),\n);\n\nfunction useHomeStorage(\n defaultWidgets: GridWidget[],\n): [GridWidget[], (value: GridWidget[]) => void] {\n const key = 'home';\n const storageApi = useApi(storageApiRef).forBucket('home.customHomepage');\n // TODO: Support multiple home pages\n const setWidgets = useCallback(\n (value: GridWidget[]) => {\n const grid: CustomHomepageGridStateV1 = {\n version: 1,\n pages: {\n default: value,\n },\n };\n storageApi.set(key, JSON.stringify(grid));\n },\n [key, storageApi],\n );\n const homeSnapshot = useObservable(\n storageApi.observe$<string>(key),\n storageApi.snapshot(key),\n );\n const widgets: GridWidget[] = useMemo(() => {\n if (homeSnapshot.presence === 'absent') {\n return defaultWidgets;\n }\n try {\n const grid: CustomHomepageGridStateV1 = JSON.parse(homeSnapshot.value!);\n return CustomHomepageGridStateV1Schema.parse(grid).pages.default;\n } catch (e) {\n return defaultWidgets;\n }\n }, [homeSnapshot, defaultWidgets]);\n\n return [widgets, setWidgets];\n}\n\nconst convertConfigToDefaultWidgets = (\n config: LayoutConfiguration[],\n availableWidgets: Widget[],\n): GridWidget[] => {\n const ret = config.map((conf, i) => {\n const c = LayoutConfigurationSchema.parse(conf);\n const name = React.isValidElement(c.component)\n ? getComponentData(c.component, 'core.extensionName')\n : (c.component as unknown as string);\n if (!name) {\n return null;\n }\n const widget = availableWidgets.find(w => w.name === name);\n if (!widget) {\n return null;\n }\n const widgetId = `${widget.name}__${i}${Math.random()\n .toString(36)\n .slice(2)}`;\n return {\n id: widgetId,\n layout: {\n i: widgetId,\n x: c.x,\n y: c.y,\n w: Math.min(widget.maxWidth ?? Number.MAX_VALUE, c.width),\n h: Math.min(widget.maxHeight ?? Number.MAX_VALUE, c.height),\n minW: widget.minWidth,\n maxW: widget.maxWidth,\n minH: widget.minHeight,\n maxH: widget.maxHeight,\n isDraggable: false,\n isResizable: false,\n },\n settings: {},\n movable: conf.movable,\n deletable: conf.deletable,\n resizable: conf.resizable,\n };\n });\n return compact(ret);\n};\n\nconst availableWidgetsFilter = (elements: ElementCollection) => {\n return elements\n .selectByComponentData({\n key: 'core.extensionName',\n })\n .getElements<Widget>()\n .flatMap(elem => {\n const config = getComponentData<CardConfig>(elem, 'home.widget.config');\n return [\n WidgetSchema.parse({\n component: elem,\n name: getComponentData<string>(elem, 'core.extensionName'),\n title: getComponentData<string>(elem, 'title'),\n description: getComponentData<string>(elem, 'description'),\n settingsSchema: config?.settings?.schema,\n uiSchema: config?.settings?.uiSchema,\n width: config?.layout?.width?.defaultColumns,\n minWidth: config?.layout?.width?.minColumns,\n maxWidth: config?.layout?.width?.maxColumns,\n height: config?.layout?.height?.defaultRows,\n minHeight: config?.layout?.height?.minRows,\n maxHeight: config?.layout?.height?.maxRows,\n }),\n ];\n });\n};\n\n/**\n * A component that allows customizing components in home grid layout.\n *\n * @public\n */\nexport const CustomHomepageGrid = (props: CustomHomepageGridProps) => {\n const styles = useStyles();\n const theme = useTheme();\n const availableWidgets = useElementFilter(\n props.children,\n availableWidgetsFilter,\n [props],\n );\n const defaultLayout = useMemo(() => {\n return props.config\n ? convertConfigToDefaultWidgets(props.config, availableWidgets)\n : [];\n }, [props.config, availableWidgets]);\n const [widgets, setWidgets] = useHomeStorage(defaultLayout);\n const [addWidgetDialogOpen, setAddWidgetDialogOpen] = React.useState(false);\n const editModeOn = widgets.find(w => w.layout.isResizable) !== undefined;\n const [editMode, setEditMode] = React.useState(editModeOn);\n const getWidgetByName = (name: string) => {\n return availableWidgets.find(widget => widget.name === name);\n };\n\n const getWidgetNameFromKey = (key: string) => {\n return key.split('__')[0];\n };\n\n const handleAdd = (widget: Widget) => {\n const widgetId = `${widget.name}__${widgets.length + 1}${Math.random()\n .toString(36)\n .slice(2)}`;\n\n setWidgets([\n ...widgets,\n {\n id: widgetId,\n layout: {\n i: widgetId,\n x: 0,\n y: Math.max(...widgets.map(w => w.layout.y + w.layout.h)) + 1,\n w: Math.min(widget.maxWidth ?? Number.MAX_VALUE, widget.width ?? 12),\n h: Math.min(widget.maxHeight ?? Number.MAX_VALUE, widget.height ?? 4),\n minW: widget.minWidth,\n maxW: widget.maxWidth,\n minH: widget.minHeight,\n maxH: widget.maxHeight,\n isResizable: editMode,\n isDraggable: editMode,\n },\n settings: {},\n movable: widget.movable,\n deletable: widget.deletable,\n resizable: widget.resizable,\n },\n ]);\n setAddWidgetDialogOpen(false);\n };\n\n const handleRemove = (widgetId: string) => {\n setWidgets(widgets.filter(w => w.id !== widgetId));\n };\n\n const handleSettingsSave = (\n widgetId: string,\n widgetSettings: Record<string, any>,\n ) => {\n const idx = widgets.findIndex(w => w.id === widgetId);\n if (idx >= 0) {\n const widget = widgets[idx];\n widget.settings = widgetSettings;\n widgets[idx] = widget;\n setWidgets(widgets);\n }\n };\n\n const clearLayout = () => {\n setWidgets([]);\n };\n\n const changeEditMode = (mode: boolean) => {\n setEditMode(mode);\n setWidgets(\n widgets.map(w => {\n const resizable = w.resizable === false ? false : mode;\n const movable = w.movable === false ? false : mode;\n return {\n ...w,\n layout: { ...w.layout, isDraggable: movable, isResizable: resizable },\n };\n }),\n );\n };\n\n const handleLayoutChange = (newLayout: Layout[], _: Layouts) => {\n if (editMode) {\n const newWidgets = newLayout.map(l => {\n const widget = widgets.find(w => w.id === l.i);\n return {\n ...widget,\n layout: l,\n } as GridWidget;\n });\n setWidgets(newWidgets);\n }\n };\n\n const handleRestoreDefaultConfig = () => {\n setWidgets(\n defaultLayout.map(w => {\n const resizable = w.resizable === false ? false : editMode;\n const movable = w.movable === false ? false : editMode;\n return {\n ...w,\n layout: {\n ...w.layout,\n isDraggable: movable,\n isResizable: resizable,\n },\n };\n }),\n );\n };\n\n return (\n <>\n <ContentHeader title=\"\">\n <CustomHomepageButtons\n editMode={editMode}\n numWidgets={widgets.length}\n clearLayout={clearLayout}\n setAddWidgetDialogOpen={setAddWidgetDialogOpen}\n changeEditMode={changeEditMode}\n defaultConfigAvailable={props.config !== undefined}\n restoreDefault={handleRestoreDefaultConfig}\n />\n </ContentHeader>\n <Dialog\n open={addWidgetDialogOpen}\n onClose={() => setAddWidgetDialogOpen(false)}\n >\n <AddWidgetDialog widgets={availableWidgets} handleAdd={handleAdd} />\n </Dialog>\n {!editMode && widgets.length === 0 && (\n <Typography variant=\"h5\" align=\"center\">\n No widgets added. Start by clicking the 'Add widget' button.\n </Typography>\n )}\n <ResponsiveGrid\n className={styles.responsiveGrid}\n measureBeforeMount\n compactType={props.compactType}\n style={props.style}\n allowOverlap={props.allowOverlap}\n preventCollision={props.preventCollision}\n draggableCancel=\".overlayGridItem,.widgetSettingsDialog,.disabled\"\n containerPadding={props.containerPadding}\n margin={props.containerMargin}\n breakpoints={\n props.breakpoints ? props.breakpoints : theme.breakpoints.values\n }\n cols={\n props.cols\n ? props.cols\n : { xl: 12, lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 }\n }\n rowHeight={props.rowHeight ?? 60}\n onLayoutChange={handleLayoutChange}\n layouts={{ xl: widgets.map(w => w.layout) }}\n >\n {widgets.map((w: GridWidget) => {\n const l = w.layout;\n const widgetName = getWidgetNameFromKey(l.i);\n const widget = getWidgetByName(widgetName);\n if (!widget || !widget.component) {\n return null;\n }\n\n const widgetProps = {\n ...widget.component.props,\n ...(w.settings ?? {}),\n };\n\n return (\n <div\n key={l.i}\n className={`${styles.widgetWrapper} ${editMode && 'edit'} ${\n w.movable === false && 'disabled'\n }`}\n >\n <ErrorBoundary>\n <widget.component.type {...widgetProps} />\n </ErrorBoundary>\n {editMode && (\n <WidgetSettingsOverlay\n id={l.i}\n widget={widget}\n handleRemove={handleRemove}\n handleSettingsSave={handleSettingsSave}\n settings={w.settings}\n deletable={w.deletable}\n />\n )}\n </div>\n );\n })}\n </ResponsiveGrid>\n </>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -2,9 +2,8 @@ import React from 'react';
|
|
|
2
2
|
import { useOutlet } from 'react-router-dom';
|
|
3
3
|
|
|
4
4
|
const HomepageCompositionRoot = (props) => {
|
|
5
|
-
var _a;
|
|
6
5
|
const outlet = useOutlet();
|
|
7
|
-
const children =
|
|
6
|
+
const children = props.children ?? outlet;
|
|
8
7
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, children);
|
|
9
8
|
};
|
|
10
9
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HomepageCompositionRoot.esm.js","sources":["../../src/components/HomepageCompositionRoot.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { ReactNode } from 'react';\nimport { useOutlet } from 'react-router-dom';\n\nexport const HomepageCompositionRoot = (props: {\n title?: string;\n children?: ReactNode;\n}) => {\n const outlet = useOutlet();\n const children = props.children ?? outlet;\n return <>{children}</>;\n};\n"],"names":[],"mappings":";;;AAmBa,MAAA,uBAAA,GAA0B,CAAC,KAGlC,KAAA;
|
|
1
|
+
{"version":3,"file":"HomepageCompositionRoot.esm.js","sources":["../../src/components/HomepageCompositionRoot.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { ReactNode } from 'react';\nimport { useOutlet } from 'react-router-dom';\n\nexport const HomepageCompositionRoot = (props: {\n title?: string;\n children?: ReactNode;\n}) => {\n const outlet = useOutlet();\n const children = props.children ?? outlet;\n return <>{children}</>;\n};\n"],"names":[],"mappings":";;;AAmBa,MAAA,uBAAA,GAA0B,CAAC,KAGlC,KAAA;AACJ,EAAA,MAAM,SAAS,SAAU,EAAA,CAAA;AACzB,EAAM,MAAA,QAAA,GAAW,MAAM,QAAY,IAAA,MAAA,CAAA;AACnC,EAAA,iEAAU,QAAS,CAAA,CAAA;AACrB;;;;"}
|
|
@@ -14,7 +14,6 @@ const StarredEntityListItem = ({
|
|
|
14
14
|
entity,
|
|
15
15
|
onToggleStarredEntity
|
|
16
16
|
}) => {
|
|
17
|
-
var _a;
|
|
18
17
|
const catalogEntityRoute = useRouteRef(entityRouteRef);
|
|
19
18
|
return /* @__PURE__ */ React.createElement(ListItem, { key: stringifyEntityRef(entity) }, /* @__PURE__ */ React.createElement(ListItemIcon, null, /* @__PURE__ */ React.createElement(Tooltip, { title: "Remove from starred" }, /* @__PURE__ */ React.createElement(
|
|
20
19
|
IconButton,
|
|
@@ -24,7 +23,7 @@ const StarredEntityListItem = ({
|
|
|
24
23
|
onClick: () => onToggleStarredEntity(entity)
|
|
25
24
|
},
|
|
26
25
|
/* @__PURE__ */ React.createElement(StarIcon, { style: { color: "#f3ba37" } })
|
|
27
|
-
))), /* @__PURE__ */ React.createElement(Link, { to: catalogEntityRoute(entityRouteParams(entity)) }, /* @__PURE__ */ React.createElement(ListItemText, { primary:
|
|
26
|
+
))), /* @__PURE__ */ React.createElement(Link, { to: catalogEntityRoute(entityRouteParams(entity)) }, /* @__PURE__ */ React.createElement(ListItemText, { primary: entity.metadata.title ?? entity.metadata.name })));
|
|
28
27
|
};
|
|
29
28
|
|
|
30
29
|
export { StarredEntityListItem };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StarredEntityListItem.esm.js","sources":["../../../src/components/StarredEntityListItem/StarredEntityListItem.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Entity, stringifyEntityRef } from '@backstage/catalog-model';\nimport { entityRouteParams } from '@backstage/plugin-catalog-react';\nimport ListItem from '@material-ui/core/ListItem';\nimport ListItemIcon from '@material-ui/core/ListItemIcon';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport IconButton from '@material-ui/core/IconButton';\nimport ListItemText from '@material-ui/core/ListItemText';\nimport React from 'react';\nimport { Link } from 'react-router-dom';\nimport { entityRouteRef } from '@backstage/plugin-catalog-react';\nimport { useRouteRef } from '@backstage/core-plugin-api';\nimport StarIcon from '@material-ui/icons/Star';\n\ntype EntityListItemProps = {\n entity: Entity;\n onToggleStarredEntity: (entity: Entity) => void;\n};\n\nexport const StarredEntityListItem = ({\n entity,\n onToggleStarredEntity,\n}: EntityListItemProps) => {\n const catalogEntityRoute = useRouteRef(entityRouteRef);\n\n return (\n <ListItem key={stringifyEntityRef(entity)}>\n <ListItemIcon>\n <Tooltip title=\"Remove from starred\">\n <IconButton\n edge=\"end\"\n aria-label=\"unstar\"\n onClick={() => onToggleStarredEntity(entity)}\n >\n <StarIcon style={{ color: '#f3ba37' }} />\n </IconButton>\n </Tooltip>\n </ListItemIcon>\n <Link to={catalogEntityRoute(entityRouteParams(entity))}>\n <ListItemText primary={entity.metadata.title ?? entity.metadata.name} />\n </Link>\n </ListItem>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;;AAiCO,MAAM,wBAAwB,CAAC;AAAA,EACpC,MAAA;AAAA,EACA,qBAAA;AACF,CAA2B,KAAA;
|
|
1
|
+
{"version":3,"file":"StarredEntityListItem.esm.js","sources":["../../../src/components/StarredEntityListItem/StarredEntityListItem.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Entity, stringifyEntityRef } from '@backstage/catalog-model';\nimport { entityRouteParams } from '@backstage/plugin-catalog-react';\nimport ListItem from '@material-ui/core/ListItem';\nimport ListItemIcon from '@material-ui/core/ListItemIcon';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport IconButton from '@material-ui/core/IconButton';\nimport ListItemText from '@material-ui/core/ListItemText';\nimport React from 'react';\nimport { Link } from 'react-router-dom';\nimport { entityRouteRef } from '@backstage/plugin-catalog-react';\nimport { useRouteRef } from '@backstage/core-plugin-api';\nimport StarIcon from '@material-ui/icons/Star';\n\ntype EntityListItemProps = {\n entity: Entity;\n onToggleStarredEntity: (entity: Entity) => void;\n};\n\nexport const StarredEntityListItem = ({\n entity,\n onToggleStarredEntity,\n}: EntityListItemProps) => {\n const catalogEntityRoute = useRouteRef(entityRouteRef);\n\n return (\n <ListItem key={stringifyEntityRef(entity)}>\n <ListItemIcon>\n <Tooltip title=\"Remove from starred\">\n <IconButton\n edge=\"end\"\n aria-label=\"unstar\"\n onClick={() => onToggleStarredEntity(entity)}\n >\n <StarIcon style={{ color: '#f3ba37' }} />\n </IconButton>\n </Tooltip>\n </ListItemIcon>\n <Link to={catalogEntityRoute(entityRouteParams(entity))}>\n <ListItemText primary={entity.metadata.title ?? entity.metadata.name} />\n </Link>\n </ListItem>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;;AAiCO,MAAM,wBAAwB,CAAC;AAAA,EACpC,MAAA;AAAA,EACA,qBAAA;AACF,CAA2B,KAAA;AACzB,EAAM,MAAA,kBAAA,GAAqB,YAAY,cAAc,CAAA,CAAA;AAErD,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,QAAS,EAAA,EAAA,GAAA,EAAK,kBAAmB,CAAA,MAAM,CACtC,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,YACC,EAAA,IAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,OAAQ,EAAA,EAAA,KAAA,EAAM,qBACb,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,UAAA;AAAA,IAAA;AAAA,MACC,IAAK,EAAA,KAAA;AAAA,MACL,YAAW,EAAA,QAAA;AAAA,MACX,OAAA,EAAS,MAAM,qBAAA,CAAsB,MAAM,CAAA;AAAA,KAAA;AAAA,wCAE1C,QAAS,EAAA,EAAA,KAAA,EAAO,EAAE,KAAA,EAAO,WAAa,EAAA,CAAA;AAAA,GAE3C,CACF,CACA,kBAAA,KAAA,CAAA,aAAA,CAAC,QAAK,EAAI,EAAA,kBAAA,CAAmB,kBAAkB,MAAM,CAAC,qBACnD,KAAA,CAAA,aAAA,CAAA,YAAA,EAAA,EAAa,SAAS,MAAO,CAAA,QAAA,CAAS,SAAS,MAAO,CAAA,QAAA,CAAS,IAAM,EAAA,CACxE,CACF,CAAA,CAAA;AAEJ;;;;"}
|
|
@@ -12,9 +12,8 @@ const useStyles = makeStyles((theme) => ({
|
|
|
12
12
|
}
|
|
13
13
|
}));
|
|
14
14
|
const maybeEntity = (visit) => {
|
|
15
|
-
var _a;
|
|
16
15
|
try {
|
|
17
|
-
return parseEntityRef(
|
|
16
|
+
return parseEntityRef(visit?.entityRef ?? "");
|
|
18
17
|
} catch (e) {
|
|
19
18
|
return void 0;
|
|
20
19
|
}
|
|
@@ -45,7 +44,6 @@ const getChipColor = (entity) => {
|
|
|
45
44
|
return foundIndex === -1 ? defaultColor : getColorByIndex(foundIndex + 1);
|
|
46
45
|
};
|
|
47
46
|
const ItemCategory = ({ visit }) => {
|
|
48
|
-
var _a;
|
|
49
47
|
const classes = useStyles();
|
|
50
48
|
const entity = maybeEntity(visit);
|
|
51
49
|
return /* @__PURE__ */ React.createElement(
|
|
@@ -53,7 +51,7 @@ const ItemCategory = ({ visit }) => {
|
|
|
53
51
|
{
|
|
54
52
|
size: "small",
|
|
55
53
|
className: classes.chip,
|
|
56
|
-
label: (
|
|
54
|
+
label: (entity?.kind ?? "Other").toLocaleLowerCase("en-US"),
|
|
57
55
|
style: { background: getChipColor(entity) }
|
|
58
56
|
}
|
|
59
57
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ItemCategory.esm.js","sources":["../../../src/components/VisitList/ItemCategory.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport Chip from '@material-ui/core/Chip';\nimport { makeStyles } from '@material-ui/core/styles';\nimport { colorVariants } from '@backstage/theme';\nimport { Visit } from '../../api/VisitsApi';\nimport { CompoundEntityRef, parseEntityRef } from '@backstage/catalog-model';\n\nconst useStyles = makeStyles(theme => ({\n chip: {\n color: theme.palette.common.white,\n fontWeight: 'bold',\n margin: 0,\n },\n}));\nconst maybeEntity = (visit: Visit): CompoundEntityRef | undefined => {\n try {\n return parseEntityRef(visit?.entityRef ?? '');\n } catch (e) {\n return undefined;\n }\n};\nconst getColorByIndex = (index: number) => {\n const variants = Object.keys(colorVariants);\n const variantIndex = index % variants.length;\n return colorVariants[variants[variantIndex]][0];\n};\nconst getChipColor = (entity: CompoundEntityRef | undefined): string => {\n const defaultColor = getColorByIndex(0);\n if (!entity) return defaultColor;\n\n // IDEA: Use or replicate useAllKinds hook thus supporting all software catalog\n // registered kinds. See:\n // plugins/catalog-react/src/components/EntityKindPicker/kindFilterUtils.ts\n // Provide extension point to register your own color code.\n const entityKinds = [\n 'component',\n 'template',\n 'api',\n 'group',\n 'user',\n 'resource',\n 'system',\n 'domain',\n 'location',\n ];\n const foundIndex = entityKinds.indexOf(\n entity.kind.toLocaleLowerCase('en-US'),\n );\n return foundIndex === -1 ? defaultColor : getColorByIndex(foundIndex + 1);\n};\n\nexport const ItemCategory = ({ visit }: { visit: Visit }) => {\n const classes = useStyles();\n const entity = maybeEntity(visit);\n\n return (\n <Chip\n size=\"small\"\n className={classes.chip}\n label={(entity?.kind ?? 'Other').toLocaleLowerCase('en-US')}\n style={{ background: getChipColor(entity) }}\n />\n );\n};\n"],"names":[],"mappings":";;;;;;AAuBA,MAAM,SAAA,GAAY,WAAW,CAAU,KAAA,MAAA;AAAA,EACrC,IAAM,EAAA;AAAA,IACJ,KAAA,EAAO,KAAM,CAAA,OAAA,CAAQ,MAAO,CAAA,KAAA;AAAA,IAC5B,UAAY,EAAA,MAAA;AAAA,IACZ,MAAQ,EAAA,CAAA;AAAA,GACV;AACF,CAAE,CAAA,CAAA,CAAA;AACF,MAAM,WAAA,GAAc,CAAC,KAAgD,KAAA;
|
|
1
|
+
{"version":3,"file":"ItemCategory.esm.js","sources":["../../../src/components/VisitList/ItemCategory.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport Chip from '@material-ui/core/Chip';\nimport { makeStyles } from '@material-ui/core/styles';\nimport { colorVariants } from '@backstage/theme';\nimport { Visit } from '../../api/VisitsApi';\nimport { CompoundEntityRef, parseEntityRef } from '@backstage/catalog-model';\n\nconst useStyles = makeStyles(theme => ({\n chip: {\n color: theme.palette.common.white,\n fontWeight: 'bold',\n margin: 0,\n },\n}));\nconst maybeEntity = (visit: Visit): CompoundEntityRef | undefined => {\n try {\n return parseEntityRef(visit?.entityRef ?? '');\n } catch (e) {\n return undefined;\n }\n};\nconst getColorByIndex = (index: number) => {\n const variants = Object.keys(colorVariants);\n const variantIndex = index % variants.length;\n return colorVariants[variants[variantIndex]][0];\n};\nconst getChipColor = (entity: CompoundEntityRef | undefined): string => {\n const defaultColor = getColorByIndex(0);\n if (!entity) return defaultColor;\n\n // IDEA: Use or replicate useAllKinds hook thus supporting all software catalog\n // registered kinds. See:\n // plugins/catalog-react/src/components/EntityKindPicker/kindFilterUtils.ts\n // Provide extension point to register your own color code.\n const entityKinds = [\n 'component',\n 'template',\n 'api',\n 'group',\n 'user',\n 'resource',\n 'system',\n 'domain',\n 'location',\n ];\n const foundIndex = entityKinds.indexOf(\n entity.kind.toLocaleLowerCase('en-US'),\n );\n return foundIndex === -1 ? defaultColor : getColorByIndex(foundIndex + 1);\n};\n\nexport const ItemCategory = ({ visit }: { visit: Visit }) => {\n const classes = useStyles();\n const entity = maybeEntity(visit);\n\n return (\n <Chip\n size=\"small\"\n className={classes.chip}\n label={(entity?.kind ?? 'Other').toLocaleLowerCase('en-US')}\n style={{ background: getChipColor(entity) }}\n />\n );\n};\n"],"names":[],"mappings":";;;;;;AAuBA,MAAM,SAAA,GAAY,WAAW,CAAU,KAAA,MAAA;AAAA,EACrC,IAAM,EAAA;AAAA,IACJ,KAAA,EAAO,KAAM,CAAA,OAAA,CAAQ,MAAO,CAAA,KAAA;AAAA,IAC5B,UAAY,EAAA,MAAA;AAAA,IACZ,MAAQ,EAAA,CAAA;AAAA,GACV;AACF,CAAE,CAAA,CAAA,CAAA;AACF,MAAM,WAAA,GAAc,CAAC,KAAgD,KAAA;AACnE,EAAI,IAAA;AACF,IAAO,OAAA,cAAA,CAAe,KAAO,EAAA,SAAA,IAAa,EAAE,CAAA,CAAA;AAAA,WACrC,CAAG,EAAA;AACV,IAAO,OAAA,KAAA,CAAA,CAAA;AAAA,GACT;AACF,CAAA,CAAA;AACA,MAAM,eAAA,GAAkB,CAAC,KAAkB,KAAA;AACzC,EAAM,MAAA,QAAA,GAAW,MAAO,CAAA,IAAA,CAAK,aAAa,CAAA,CAAA;AAC1C,EAAM,MAAA,YAAA,GAAe,QAAQ,QAAS,CAAA,MAAA,CAAA;AACtC,EAAA,OAAO,aAAc,CAAA,QAAA,CAAS,YAAY,CAAC,EAAE,CAAC,CAAA,CAAA;AAChD,CAAA,CAAA;AACA,MAAM,YAAA,GAAe,CAAC,MAAkD,KAAA;AACtE,EAAM,MAAA,YAAA,GAAe,gBAAgB,CAAC,CAAA,CAAA;AACtC,EAAA,IAAI,CAAC,MAAA;AAAQ,IAAO,OAAA,YAAA,CAAA;AAMpB,EAAA,MAAM,WAAc,GAAA;AAAA,IAClB,WAAA;AAAA,IACA,UAAA;AAAA,IACA,KAAA;AAAA,IACA,OAAA;AAAA,IACA,MAAA;AAAA,IACA,UAAA;AAAA,IACA,QAAA;AAAA,IACA,QAAA;AAAA,IACA,UAAA;AAAA,GACF,CAAA;AACA,EAAA,MAAM,aAAa,WAAY,CAAA,OAAA;AAAA,IAC7B,MAAA,CAAO,IAAK,CAAA,iBAAA,CAAkB,OAAO,CAAA;AAAA,GACvC,CAAA;AACA,EAAA,OAAO,UAAe,KAAA,CAAA,CAAA,GAAK,YAAe,GAAA,eAAA,CAAgB,aAAa,CAAC,CAAA,CAAA;AAC1E,CAAA,CAAA;AAEO,MAAM,YAAe,GAAA,CAAC,EAAE,KAAA,EAA8B,KAAA;AAC3D,EAAA,MAAM,UAAU,SAAU,EAAA,CAAA;AAC1B,EAAM,MAAA,MAAA,GAAS,YAAY,KAAK,CAAA,CAAA;AAEhC,EACE,uBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,IAAA;AAAA,IAAA;AAAA,MACC,IAAK,EAAA,OAAA;AAAA,MACL,WAAW,OAAQ,CAAA,IAAA;AAAA,MACnB,KAAQ,EAAA,CAAA,MAAA,EAAQ,IAAQ,IAAA,OAAA,EAAS,kBAAkB,OAAO,CAAA;AAAA,MAC1D,KAAO,EAAA,EAAE,UAAY,EAAA,YAAA,CAAa,MAAM,CAAE,EAAA;AAAA,KAAA;AAAA,GAC5C,CAAA;AAEJ;;;;"}
|
|
@@ -4,7 +4,6 @@ import { DateTime } from 'luxon';
|
|
|
4
4
|
|
|
5
5
|
const ItemDetailHits = ({ visit }) => /* @__PURE__ */ React.createElement(Typography, { component: "span", variant: "caption", color: "textSecondary" }, visit.hits, " time", visit.hits > 1 ? "s" : "");
|
|
6
6
|
const ItemDetailTimeAgo = ({ visit }) => {
|
|
7
|
-
var _a;
|
|
8
7
|
const visitDate = DateTime.fromMillis(visit.timestamp);
|
|
9
8
|
return /* @__PURE__ */ React.createElement(
|
|
10
9
|
Typography,
|
|
@@ -12,7 +11,7 @@ const ItemDetailTimeAgo = ({ visit }) => {
|
|
|
12
11
|
component: "time",
|
|
13
12
|
variant: "caption",
|
|
14
13
|
color: "textSecondary",
|
|
15
|
-
dateTime:
|
|
14
|
+
dateTime: visitDate.toISO() ?? void 0
|
|
16
15
|
},
|
|
17
16
|
visitDate.toRelative()
|
|
18
17
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ItemDetail.esm.js","sources":["../../../src/components/VisitList/ItemDetail.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport Typography from '@material-ui/core/Typography';\nimport { Visit } from '../../api/VisitsApi';\nimport { DateTime } from 'luxon';\n\nconst ItemDetailHits = ({ visit }: { visit: Visit }) => (\n <Typography component=\"span\" variant=\"caption\" color=\"textSecondary\">\n {visit.hits} time{visit.hits > 1 ? 's' : ''}\n </Typography>\n);\n\nconst ItemDetailTimeAgo = ({ visit }: { visit: Visit }) => {\n const visitDate = DateTime.fromMillis(visit.timestamp);\n\n return (\n <Typography\n component=\"time\"\n variant=\"caption\"\n color=\"textSecondary\"\n dateTime={visitDate.toISO() ?? undefined}\n >\n {visitDate.toRelative()}\n </Typography>\n );\n};\n\nexport type ItemDetailType = 'time-ago' | 'hits';\n\nexport const ItemDetail = ({\n visit,\n type,\n}: {\n visit: Visit;\n type: ItemDetailType;\n}) =>\n type === 'time-ago' ? (\n <ItemDetailTimeAgo visit={visit} />\n ) : (\n <ItemDetailHits visit={visit} />\n );\n"],"names":[],"mappings":";;;;AAqBA,MAAM,cAAA,GAAiB,CAAC,EAAE,KAAA,uBACvB,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,WAAU,MAAO,EAAA,OAAA,EAAQ,WAAU,KAAM,EAAA,eAAA,EAAA,EAClD,MAAM,IAAK,EAAA,OAAA,EAAM,MAAM,IAAO,GAAA,CAAA,GAAI,MAAM,EAC3C,CAAA,CAAA;AAGF,MAAM,iBAAoB,GAAA,CAAC,EAAE,KAAA,EAA8B,KAAA;
|
|
1
|
+
{"version":3,"file":"ItemDetail.esm.js","sources":["../../../src/components/VisitList/ItemDetail.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport Typography from '@material-ui/core/Typography';\nimport { Visit } from '../../api/VisitsApi';\nimport { DateTime } from 'luxon';\n\nconst ItemDetailHits = ({ visit }: { visit: Visit }) => (\n <Typography component=\"span\" variant=\"caption\" color=\"textSecondary\">\n {visit.hits} time{visit.hits > 1 ? 's' : ''}\n </Typography>\n);\n\nconst ItemDetailTimeAgo = ({ visit }: { visit: Visit }) => {\n const visitDate = DateTime.fromMillis(visit.timestamp);\n\n return (\n <Typography\n component=\"time\"\n variant=\"caption\"\n color=\"textSecondary\"\n dateTime={visitDate.toISO() ?? undefined}\n >\n {visitDate.toRelative()}\n </Typography>\n );\n};\n\nexport type ItemDetailType = 'time-ago' | 'hits';\n\nexport const ItemDetail = ({\n visit,\n type,\n}: {\n visit: Visit;\n type: ItemDetailType;\n}) =>\n type === 'time-ago' ? (\n <ItemDetailTimeAgo visit={visit} />\n ) : (\n <ItemDetailHits visit={visit} />\n );\n"],"names":[],"mappings":";;;;AAqBA,MAAM,cAAA,GAAiB,CAAC,EAAE,KAAA,uBACvB,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,WAAU,MAAO,EAAA,OAAA,EAAQ,WAAU,KAAM,EAAA,eAAA,EAAA,EAClD,MAAM,IAAK,EAAA,OAAA,EAAM,MAAM,IAAO,GAAA,CAAA,GAAI,MAAM,EAC3C,CAAA,CAAA;AAGF,MAAM,iBAAoB,GAAA,CAAC,EAAE,KAAA,EAA8B,KAAA;AACzD,EAAA,MAAM,SAAY,GAAA,QAAA,CAAS,UAAW,CAAA,KAAA,CAAM,SAAS,CAAA,CAAA;AAErD,EACE,uBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,UAAA;AAAA,IAAA;AAAA,MACC,SAAU,EAAA,MAAA;AAAA,MACV,OAAQ,EAAA,SAAA;AAAA,MACR,KAAM,EAAA,eAAA;AAAA,MACN,QAAA,EAAU,SAAU,CAAA,KAAA,EAAW,IAAA,KAAA,CAAA;AAAA,KAAA;AAAA,IAE9B,UAAU,UAAW,EAAA;AAAA,GACxB,CAAA;AAEJ,CAAA,CAAA;AAIO,MAAM,aAAa,CAAC;AAAA,EACzB,KAAA;AAAA,EACA,IAAA;AACF,CAIE,KAAA,IAAA,KAAS,6BACN,KAAA,CAAA,aAAA,CAAA,iBAAA,EAAA,EAAkB,OAAc,CAEjC,mBAAA,KAAA,CAAA,aAAA,CAAC,kBAAe,KAAc,EAAA;;;;"}
|
|
@@ -13,7 +13,7 @@ const getToEntityRef = ({
|
|
|
13
13
|
`^/${rootPath}/(?<namespace>[^/]+)/(?<kind>[^/]+)/(?<name>[^/]+)`
|
|
14
14
|
);
|
|
15
15
|
const result = regex.exec(pathname);
|
|
16
|
-
if (!result || !
|
|
16
|
+
if (!result || !result?.groups)
|
|
17
17
|
return void 0;
|
|
18
18
|
const entity = {
|
|
19
19
|
namespace: result.groups.namespace,
|
|
@@ -27,10 +27,10 @@ const getVisitName = ({ rootPath = "catalog", document = global.document } = {})
|
|
|
27
27
|
`^/${rootPath}/(?<namespace>[^/]+)/(?<kind>[^/]+)/(?<name>[^/]+)`
|
|
28
28
|
);
|
|
29
29
|
let result = regex.exec(pathname);
|
|
30
|
-
if (result &&
|
|
30
|
+
if (result && result?.groups)
|
|
31
31
|
return result.groups.name;
|
|
32
32
|
result = /^\/(?<name>[^\/]+)$/.exec(pathname);
|
|
33
|
-
if (result &&
|
|
33
|
+
if (result && result?.groups)
|
|
34
34
|
return result.groups.name;
|
|
35
35
|
return document.title;
|
|
36
36
|
};
|
|
@@ -41,8 +41,8 @@ const VisitListener = ({
|
|
|
41
41
|
}) => {
|
|
42
42
|
const visitsApi = useApi(visitsApiRef);
|
|
43
43
|
const { pathname } = useLocation();
|
|
44
|
-
const toEntityRefImpl = toEntityRef
|
|
45
|
-
const visitNameImpl = visitName
|
|
44
|
+
const toEntityRefImpl = toEntityRef ?? getToEntityRef();
|
|
45
|
+
const visitNameImpl = visitName ?? getVisitName();
|
|
46
46
|
useEffect(() => {
|
|
47
47
|
const requestId = requestAnimationFrame(() => {
|
|
48
48
|
visitsApi.save({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VisitListener.esm.js","sources":["../../src/components/VisitListener.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React, { useEffect } from 'react';\n\nimport { useLocation } from 'react-router-dom';\n\nimport { visitsApiRef } from '../api';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { stringifyEntityRef } from '@backstage/catalog-model';\n\n/**\n * This function returns an implementation of toEntityRef which is responsible\n * for receiving a pathname and maybe returning an entityRef compatible with the\n * catalog-model.\n * By default this function uses the url root \"/catalog\" and the\n * stringifyEntityRef implementation from catalog-model.\n * Example:\n * const toEntityRef = getToEntityRef();\n * toEntityRef(\\{ pathname: \"/catalog/default/component/playback-order\" \\})\n * // returns \"component:default/playback-order\"\n */\nconst getToEntityRef =\n ({\n rootPath = 'catalog',\n stringifyEntityRefImpl = stringifyEntityRef,\n } = {}) =>\n ({ pathname }: { pathname: string }): string | undefined => {\n const regex = new RegExp(\n `^\\/${rootPath}\\/(?<namespace>[^\\/]+)\\/(?<kind>[^\\/]+)\\/(?<name>[^\\/]+)`,\n );\n const result = regex.exec(pathname);\n if (!result || !result?.groups) return undefined;\n const entity = {\n namespace: result.groups.namespace,\n kind: result.groups.kind,\n name: result.groups.name,\n };\n return stringifyEntityRefImpl(entity);\n };\n\n/**\n * @internal\n * This function returns an implementation of visitName which is responsible\n * for receiving a pathname and returning a string (name).\n */\nconst getVisitName =\n ({ rootPath = 'catalog', document = global.document } = {}) =>\n ({ pathname }: { pathname: string }) => {\n // If it is a catalog entity, get the name from the path\n const regex = new RegExp(\n `^\\/${rootPath}\\/(?<namespace>[^\\/]+)\\/(?<kind>[^\\/]+)\\/(?<name>[^\\/]+)`,\n );\n let result = regex.exec(pathname);\n if (result && result?.groups) return result.groups.name;\n\n // If it is a root pathname, get the name from there\n result = /^\\/(?<name>[^\\/]+)$/.exec(pathname);\n if (result && result?.groups) return result.groups.name;\n\n // Fallback to document title\n return document.title;\n };\n\n/**\n * @public\n * Component responsible for listening to location changes and calling\n * the visitsApi to save visits.\n */\nexport const VisitListener = ({\n children,\n toEntityRef,\n visitName,\n}: {\n children?: React.ReactNode;\n toEntityRef?: ({ pathname }: { pathname: string }) => string | undefined;\n visitName?: ({ pathname }: { pathname: string }) => string;\n}): JSX.Element => {\n const visitsApi = useApi(visitsApiRef);\n const { pathname } = useLocation();\n const toEntityRefImpl = toEntityRef ?? getToEntityRef();\n const visitNameImpl = visitName ?? getVisitName();\n useEffect(() => {\n // Wait for the browser to finish with paint with the assumption react\n // has finished with dom reconciliation.\n const requestId = requestAnimationFrame(() => {\n visitsApi.save({\n visit: {\n name: visitNameImpl({ pathname }),\n pathname,\n entityRef: toEntityRefImpl({ pathname }),\n },\n });\n });\n return () => cancelAnimationFrame(requestId);\n }, [visitsApi, pathname, toEntityRefImpl, visitNameImpl]);\n\n return <>{children}</>;\n};\n"],"names":[],"mappings":";;;;;;;AAkCA,MAAM,iBACJ,CAAC;AAAA,EACC,QAAW,GAAA,SAAA;AAAA,EACX,sBAAyB,GAAA,kBAAA;AAC3B,CAAA,GAAI,EAAC,KACL,CAAC,EAAE,UAAyD,KAAA;AAC1D,EAAA,MAAM,QAAQ,IAAI,MAAA;AAAA,IAChB,KAAM,QAAQ,CAAA,kDAAA,CAAA;AAAA,GAChB,CAAA;AACA,EAAM,MAAA,MAAA,GAAS,KAAM,CAAA,IAAA,CAAK,QAAQ,CAAA,CAAA;AAClC,EAAI,IAAA,CAAC,MAAU,IAAA,
|
|
1
|
+
{"version":3,"file":"VisitListener.esm.js","sources":["../../src/components/VisitListener.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React, { useEffect } from 'react';\n\nimport { useLocation } from 'react-router-dom';\n\nimport { visitsApiRef } from '../api';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { stringifyEntityRef } from '@backstage/catalog-model';\n\n/**\n * This function returns an implementation of toEntityRef which is responsible\n * for receiving a pathname and maybe returning an entityRef compatible with the\n * catalog-model.\n * By default this function uses the url root \"/catalog\" and the\n * stringifyEntityRef implementation from catalog-model.\n * Example:\n * const toEntityRef = getToEntityRef();\n * toEntityRef(\\{ pathname: \"/catalog/default/component/playback-order\" \\})\n * // returns \"component:default/playback-order\"\n */\nconst getToEntityRef =\n ({\n rootPath = 'catalog',\n stringifyEntityRefImpl = stringifyEntityRef,\n } = {}) =>\n ({ pathname }: { pathname: string }): string | undefined => {\n const regex = new RegExp(\n `^\\/${rootPath}\\/(?<namespace>[^\\/]+)\\/(?<kind>[^\\/]+)\\/(?<name>[^\\/]+)`,\n );\n const result = regex.exec(pathname);\n if (!result || !result?.groups) return undefined;\n const entity = {\n namespace: result.groups.namespace,\n kind: result.groups.kind,\n name: result.groups.name,\n };\n return stringifyEntityRefImpl(entity);\n };\n\n/**\n * @internal\n * This function returns an implementation of visitName which is responsible\n * for receiving a pathname and returning a string (name).\n */\nconst getVisitName =\n ({ rootPath = 'catalog', document = global.document } = {}) =>\n ({ pathname }: { pathname: string }) => {\n // If it is a catalog entity, get the name from the path\n const regex = new RegExp(\n `^\\/${rootPath}\\/(?<namespace>[^\\/]+)\\/(?<kind>[^\\/]+)\\/(?<name>[^\\/]+)`,\n );\n let result = regex.exec(pathname);\n if (result && result?.groups) return result.groups.name;\n\n // If it is a root pathname, get the name from there\n result = /^\\/(?<name>[^\\/]+)$/.exec(pathname);\n if (result && result?.groups) return result.groups.name;\n\n // Fallback to document title\n return document.title;\n };\n\n/**\n * @public\n * Component responsible for listening to location changes and calling\n * the visitsApi to save visits.\n */\nexport const VisitListener = ({\n children,\n toEntityRef,\n visitName,\n}: {\n children?: React.ReactNode;\n toEntityRef?: ({ pathname }: { pathname: string }) => string | undefined;\n visitName?: ({ pathname }: { pathname: string }) => string;\n}): JSX.Element => {\n const visitsApi = useApi(visitsApiRef);\n const { pathname } = useLocation();\n const toEntityRefImpl = toEntityRef ?? getToEntityRef();\n const visitNameImpl = visitName ?? getVisitName();\n useEffect(() => {\n // Wait for the browser to finish with paint with the assumption react\n // has finished with dom reconciliation.\n const requestId = requestAnimationFrame(() => {\n visitsApi.save({\n visit: {\n name: visitNameImpl({ pathname }),\n pathname,\n entityRef: toEntityRefImpl({ pathname }),\n },\n });\n });\n return () => cancelAnimationFrame(requestId);\n }, [visitsApi, pathname, toEntityRefImpl, visitNameImpl]);\n\n return <>{children}</>;\n};\n"],"names":[],"mappings":";;;;;;;AAkCA,MAAM,iBACJ,CAAC;AAAA,EACC,QAAW,GAAA,SAAA;AAAA,EACX,sBAAyB,GAAA,kBAAA;AAC3B,CAAA,GAAI,EAAC,KACL,CAAC,EAAE,UAAyD,KAAA;AAC1D,EAAA,MAAM,QAAQ,IAAI,MAAA;AAAA,IAChB,KAAM,QAAQ,CAAA,kDAAA,CAAA;AAAA,GAChB,CAAA;AACA,EAAM,MAAA,MAAA,GAAS,KAAM,CAAA,IAAA,CAAK,QAAQ,CAAA,CAAA;AAClC,EAAI,IAAA,CAAC,MAAU,IAAA,CAAC,MAAQ,EAAA,MAAA;AAAQ,IAAO,OAAA,KAAA,CAAA,CAAA;AACvC,EAAA,MAAM,MAAS,GAAA;AAAA,IACb,SAAA,EAAW,OAAO,MAAO,CAAA,SAAA;AAAA,IACzB,IAAA,EAAM,OAAO,MAAO,CAAA,IAAA;AAAA,IACpB,IAAA,EAAM,OAAO,MAAO,CAAA,IAAA;AAAA,GACtB,CAAA;AACA,EAAA,OAAO,uBAAuB,MAAM,CAAA,CAAA;AACtC,CAAA,CAAA;AAOF,MAAM,YACJ,GAAA,CAAC,EAAE,QAAA,GAAW,WAAW,QAAW,GAAA,MAAA,CAAO,QAAS,EAAA,GAAI,EAAC,KACzD,CAAC,EAAE,UAAqC,KAAA;AAEtC,EAAA,MAAM,QAAQ,IAAI,MAAA;AAAA,IAChB,KAAM,QAAQ,CAAA,kDAAA,CAAA;AAAA,GAChB,CAAA;AACA,EAAI,IAAA,MAAA,GAAS,KAAM,CAAA,IAAA,CAAK,QAAQ,CAAA,CAAA;AAChC,EAAA,IAAI,UAAU,MAAQ,EAAA,MAAA;AAAQ,IAAA,OAAO,OAAO,MAAO,CAAA,IAAA,CAAA;AAGnD,EAAS,MAAA,GAAA,qBAAA,CAAsB,KAAK,QAAQ,CAAA,CAAA;AAC5C,EAAA,IAAI,UAAU,MAAQ,EAAA,MAAA;AAAQ,IAAA,OAAO,OAAO,MAAO,CAAA,IAAA,CAAA;AAGnD,EAAA,OAAO,QAAS,CAAA,KAAA,CAAA;AAClB,CAAA,CAAA;AAOK,MAAM,gBAAgB,CAAC;AAAA,EAC5B,QAAA;AAAA,EACA,WAAA;AAAA,EACA,SAAA;AACF,CAImB,KAAA;AACjB,EAAM,MAAA,SAAA,GAAY,OAAO,YAAY,CAAA,CAAA;AACrC,EAAM,MAAA,EAAE,QAAS,EAAA,GAAI,WAAY,EAAA,CAAA;AACjC,EAAM,MAAA,eAAA,GAAkB,eAAe,cAAe,EAAA,CAAA;AACtD,EAAM,MAAA,aAAA,GAAgB,aAAa,YAAa,EAAA,CAAA;AAChD,EAAA,SAAA,CAAU,MAAM;AAGd,IAAM,MAAA,SAAA,GAAY,sBAAsB,MAAM;AAC5C,MAAA,SAAA,CAAU,IAAK,CAAA;AAAA,QACb,KAAO,EAAA;AAAA,UACL,IAAM,EAAA,aAAA,CAAc,EAAE,QAAA,EAAU,CAAA;AAAA,UAChC,QAAA;AAAA,UACA,SAAW,EAAA,eAAA,CAAgB,EAAE,QAAA,EAAU,CAAA;AAAA,SACzC;AAAA,OACD,CAAA,CAAA;AAAA,KACF,CAAA,CAAA;AACD,IAAO,OAAA,MAAM,qBAAqB,SAAS,CAAA,CAAA;AAAA,KAC1C,CAAC,SAAA,EAAW,QAAU,EAAA,eAAA,EAAiB,aAAa,CAAC,CAAA,CAAA;AAExD,EAAA,iEAAU,QAAS,CAAA,CAAA;AACrB;;;;"}
|
|
@@ -50,7 +50,7 @@ const Content = (props) => {
|
|
|
50
50
|
if (error) {
|
|
51
51
|
return /* @__PURE__ */ React.createElement(ErrorPanel, { error });
|
|
52
52
|
}
|
|
53
|
-
return
|
|
53
|
+
return entities?.length ? /* @__PURE__ */ React.createElement(React.Fragment, null, entities.map((d) => /* @__PURE__ */ React.createElement(
|
|
54
54
|
"div",
|
|
55
55
|
{
|
|
56
56
|
key: `${d.metadata.name}-${d.kind}-${d.metadata.namespace}`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Content.esm.js","sources":["../../../src/homePageComponents/FeaturedDocsCard/Content.tsx"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport useAsync from 'react-use/esm/useAsync';\nimport {\n LinkButton,\n EmptyState,\n Link,\n Progress,\n ErrorPanel,\n} from '@backstage/core-components';\nimport {\n catalogApiRef,\n CatalogApi,\n EntityDisplayName,\n} from '@backstage/plugin-catalog-react';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { EntityFilterQuery } from '@backstage/catalog-client';\n\nimport Typography from '@material-ui/core/Typography';\nimport { makeStyles } from '@material-ui/core/styles';\nimport { stringifyEntityRef } from '@backstage/catalog-model';\n\n/**\n * Props customizing the <FeaturedDocsCard/> component.\n *\n * @public\n */\nexport type FeaturedDocsCardProps = {\n /** The entity filter used to display only the intended item/s */\n filter: EntityFilterQuery;\n /** An optional ReactNode for empty states */\n emptyState?: React.JSX.Element;\n /** An optional linkDestination to set for the Featured Doc */\n linkDestination?: string;\n /** An optional limit to set for link destination */\n responseLimit?: number;\n /** An optional string to customize sublink text */\n subLinkText?: string;\n};\n\nconst useStyles = makeStyles(\n theme => ({\n docDescription: {\n fontSize: theme.typography.body1.fontSize,\n fontWeight: theme.typography.body1.fontWeight,\n marginBottom: theme.spacing(2),\n marginTop: theme.spacing(2),\n },\n docSubLink: {\n fontSize: theme.typography.subtitle1.fontSize,\n fontWeight: theme.typography.subtitle1.fontWeight,\n lineHeight: theme.typography.subtitle1.lineHeight,\n },\n docsTitleLink: {\n fontSize: theme.typography.h6.fontSize,\n fontWeight: theme.typography.h6.fontWeight,\n lineHeight: theme.typography.h6.lineHeight,\n },\n }),\n { name: 'HomeFeaturedDocsCard' },\n);\n\n/**\n * A component to display specific Featured Docs.\n *\n * @public\n */\nexport const Content = (props: FeaturedDocsCardProps): JSX.Element => {\n const { emptyState, filter, linkDestination, responseLimit, subLinkText } =\n props;\n const linkText = subLinkText || 'LEARN MORE';\n const styles = useStyles();\n const catalogApi: CatalogApi = useApi(catalogApiRef);\n const {\n value: entities,\n loading,\n error,\n } = useAsync(async () => {\n const response = await catalogApi.getEntities({\n filter: filter,\n limit: responseLimit || 10,\n });\n return response.items;\n });\n\n if (loading) {\n return <Progress />;\n }\n if (error) {\n return <ErrorPanel error={error} />;\n }\n\n return entities?.length ? (\n <>\n {entities.map(d => (\n <div\n key={`${d.metadata.name}-${d.kind}-${d.metadata.namespace}`}\n data-testid=\"docs-card-content\"\n >\n <Link\n className={styles.docsTitleLink}\n data-testid=\"docs-card-title\"\n to={\n linkDestination ||\n `/docs/${d.metadata.namespace || 'default'}/${d.kind}/${\n d.metadata.name\n }/`\n }\n >\n <EntityDisplayName entityRef={stringifyEntityRef(d)} />\n </Link>\n {d.metadata.description && (\n <Typography className={styles.docDescription}>\n {d.metadata.description}\n </Typography>\n )}\n <Link\n className={styles.docSubLink}\n data-testid=\"docs-card-sub-link\"\n to={\n linkDestination ||\n `/docs/${d.metadata.namespace || 'default'}/${d.kind}/${\n d.metadata.name\n }/`\n }\n >\n {linkText}\n </Link>\n </div>\n ))}\n </>\n ) : (\n emptyState || (\n <EmptyState\n missing=\"data\"\n title=\"No documents to show\"\n description=\"Create your own document. Check out our Getting Started Information\"\n action={\n <LinkButton\n to=\"https://backstage.io/docs/features/techdocs/getting-started\"\n variant=\"contained\"\n >\n DOCS\n </LinkButton>\n }\n />\n )\n );\n};\n"],"names":[],"mappings":";;;;;;;;;AAuDA,MAAM,SAAY,GAAA,UAAA;AAAA,EAChB,CAAU,KAAA,MAAA;AAAA,IACR,cAAgB,EAAA;AAAA,MACd,QAAA,EAAU,KAAM,CAAA,UAAA,CAAW,KAAM,CAAA,QAAA;AAAA,MACjC,UAAA,EAAY,KAAM,CAAA,UAAA,CAAW,KAAM,CAAA,UAAA;AAAA,MACnC,YAAA,EAAc,KAAM,CAAA,OAAA,CAAQ,CAAC,CAAA;AAAA,MAC7B,SAAA,EAAW,KAAM,CAAA,OAAA,CAAQ,CAAC,CAAA;AAAA,KAC5B;AAAA,IACA,UAAY,EAAA;AAAA,MACV,QAAA,EAAU,KAAM,CAAA,UAAA,CAAW,SAAU,CAAA,QAAA;AAAA,MACrC,UAAA,EAAY,KAAM,CAAA,UAAA,CAAW,SAAU,CAAA,UAAA;AAAA,MACvC,UAAA,EAAY,KAAM,CAAA,UAAA,CAAW,SAAU,CAAA,UAAA;AAAA,KACzC;AAAA,IACA,aAAe,EAAA;AAAA,MACb,QAAA,EAAU,KAAM,CAAA,UAAA,CAAW,EAAG,CAAA,QAAA;AAAA,MAC9B,UAAA,EAAY,KAAM,CAAA,UAAA,CAAW,EAAG,CAAA,UAAA;AAAA,MAChC,UAAA,EAAY,KAAM,CAAA,UAAA,CAAW,EAAG,CAAA,UAAA;AAAA,KAClC;AAAA,GACF,CAAA;AAAA,EACA,EAAE,MAAM,sBAAuB,EAAA;AACjC,CAAA,CAAA;AAOa,MAAA,OAAA,GAAU,CAAC,KAA8C,KAAA;AACpE,EAAA,MAAM,EAAE,UAAY,EAAA,MAAA,EAAQ,eAAiB,EAAA,aAAA,EAAe,aAC1D,GAAA,KAAA,CAAA;AACF,EAAA,MAAM,WAAW,WAAe,IAAA,YAAA,CAAA;AAChC,EAAA,MAAM,SAAS,SAAU,EAAA,CAAA;AACzB,EAAM,MAAA,UAAA,GAAyB,OAAO,aAAa,CAAA,CAAA;AACnD,EAAM,MAAA;AAAA,IACJ,KAAO,EAAA,QAAA;AAAA,IACP,OAAA;AAAA,IACA,KAAA;AAAA,GACF,GAAI,SAAS,YAAY;AACvB,IAAM,MAAA,QAAA,GAAW,MAAM,UAAA,CAAW,WAAY,CAAA;AAAA,MAC5C,MAAA;AAAA,MACA,OAAO,aAAiB,IAAA,EAAA;AAAA,KACzB,CAAA,CAAA;AACD,IAAA,OAAO,QAAS,CAAA,KAAA,CAAA;AAAA,GACjB,CAAA,CAAA;AAED,EAAA,IAAI,OAAS,EAAA;AACX,IAAA,2CAAQ,QAAS,EAAA,IAAA,CAAA,CAAA;AAAA,GACnB;AACA,EAAA,IAAI,KAAO,EAAA;AACT,IAAO,uBAAA,KAAA,CAAA,aAAA,CAAC,cAAW,KAAc,EAAA,CAAA,CAAA;AAAA,GACnC;AAEA,EAAA,
|
|
1
|
+
{"version":3,"file":"Content.esm.js","sources":["../../../src/homePageComponents/FeaturedDocsCard/Content.tsx"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport useAsync from 'react-use/esm/useAsync';\nimport {\n LinkButton,\n EmptyState,\n Link,\n Progress,\n ErrorPanel,\n} from '@backstage/core-components';\nimport {\n catalogApiRef,\n CatalogApi,\n EntityDisplayName,\n} from '@backstage/plugin-catalog-react';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { EntityFilterQuery } from '@backstage/catalog-client';\n\nimport Typography from '@material-ui/core/Typography';\nimport { makeStyles } from '@material-ui/core/styles';\nimport { stringifyEntityRef } from '@backstage/catalog-model';\n\n/**\n * Props customizing the <FeaturedDocsCard/> component.\n *\n * @public\n */\nexport type FeaturedDocsCardProps = {\n /** The entity filter used to display only the intended item/s */\n filter: EntityFilterQuery;\n /** An optional ReactNode for empty states */\n emptyState?: React.JSX.Element;\n /** An optional linkDestination to set for the Featured Doc */\n linkDestination?: string;\n /** An optional limit to set for link destination */\n responseLimit?: number;\n /** An optional string to customize sublink text */\n subLinkText?: string;\n};\n\nconst useStyles = makeStyles(\n theme => ({\n docDescription: {\n fontSize: theme.typography.body1.fontSize,\n fontWeight: theme.typography.body1.fontWeight,\n marginBottom: theme.spacing(2),\n marginTop: theme.spacing(2),\n },\n docSubLink: {\n fontSize: theme.typography.subtitle1.fontSize,\n fontWeight: theme.typography.subtitle1.fontWeight,\n lineHeight: theme.typography.subtitle1.lineHeight,\n },\n docsTitleLink: {\n fontSize: theme.typography.h6.fontSize,\n fontWeight: theme.typography.h6.fontWeight,\n lineHeight: theme.typography.h6.lineHeight,\n },\n }),\n { name: 'HomeFeaturedDocsCard' },\n);\n\n/**\n * A component to display specific Featured Docs.\n *\n * @public\n */\nexport const Content = (props: FeaturedDocsCardProps): JSX.Element => {\n const { emptyState, filter, linkDestination, responseLimit, subLinkText } =\n props;\n const linkText = subLinkText || 'LEARN MORE';\n const styles = useStyles();\n const catalogApi: CatalogApi = useApi(catalogApiRef);\n const {\n value: entities,\n loading,\n error,\n } = useAsync(async () => {\n const response = await catalogApi.getEntities({\n filter: filter,\n limit: responseLimit || 10,\n });\n return response.items;\n });\n\n if (loading) {\n return <Progress />;\n }\n if (error) {\n return <ErrorPanel error={error} />;\n }\n\n return entities?.length ? (\n <>\n {entities.map(d => (\n <div\n key={`${d.metadata.name}-${d.kind}-${d.metadata.namespace}`}\n data-testid=\"docs-card-content\"\n >\n <Link\n className={styles.docsTitleLink}\n data-testid=\"docs-card-title\"\n to={\n linkDestination ||\n `/docs/${d.metadata.namespace || 'default'}/${d.kind}/${\n d.metadata.name\n }/`\n }\n >\n <EntityDisplayName entityRef={stringifyEntityRef(d)} />\n </Link>\n {d.metadata.description && (\n <Typography className={styles.docDescription}>\n {d.metadata.description}\n </Typography>\n )}\n <Link\n className={styles.docSubLink}\n data-testid=\"docs-card-sub-link\"\n to={\n linkDestination ||\n `/docs/${d.metadata.namespace || 'default'}/${d.kind}/${\n d.metadata.name\n }/`\n }\n >\n {linkText}\n </Link>\n </div>\n ))}\n </>\n ) : (\n emptyState || (\n <EmptyState\n missing=\"data\"\n title=\"No documents to show\"\n description=\"Create your own document. Check out our Getting Started Information\"\n action={\n <LinkButton\n to=\"https://backstage.io/docs/features/techdocs/getting-started\"\n variant=\"contained\"\n >\n DOCS\n </LinkButton>\n }\n />\n )\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -16,7 +16,7 @@ function getTimes(clockConfigs, customTimeFormat) {
|
|
|
16
16
|
let label = clockConfig.label;
|
|
17
17
|
const options = {
|
|
18
18
|
timeZone: clockConfig.timeZone,
|
|
19
|
-
...customTimeFormat
|
|
19
|
+
...customTimeFormat ?? timeFormat
|
|
20
20
|
};
|
|
21
21
|
try {
|
|
22
22
|
(/* @__PURE__ */ new Date()).toLocaleString(lang, options);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HeaderWorldClock.esm.js","sources":["../../../src/homePageComponents/HeaderWorldClock/HeaderWorldClock.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport { HeaderLabel } from '@backstage/core-components';\n\nconst timeFormat: Intl.DateTimeFormatOptions = {\n hour: '2-digit',\n minute: '2-digit',\n};\n\ntype TimeObj = {\n label: string;\n value: string;\n dateTime: string;\n};\n\n/** @public */\nexport type ClockConfig = {\n label: string;\n timeZone: string;\n};\n\nfunction getTimes(\n clockConfigs: ClockConfig[],\n customTimeFormat?: Intl.DateTimeFormatOptions,\n) {\n const d = new Date();\n const lang = window.navigator.language;\n\n const clocks: TimeObj[] = [];\n\n if (!clockConfigs) {\n return clocks;\n }\n\n for (const clockConfig of clockConfigs) {\n let label = clockConfig.label;\n\n const options: Intl.DateTimeFormatOptions = {\n timeZone: clockConfig.timeZone,\n ...(customTimeFormat ?? timeFormat),\n };\n\n try {\n new Date().toLocaleString(lang, options);\n } catch (e) {\n // eslint-disable-next-line no-console\n console.warn(\n `The timezone ${options.timeZone} is invalid. Defaulting to GMT`,\n );\n options.timeZone = 'GMT';\n label = 'GMT';\n }\n\n const value = d.toLocaleTimeString(lang, options);\n const dateTime = d.toLocaleTimeString(lang, {\n timeZone: options.timeZone,\n hour: '2-digit',\n minute: '2-digit',\n hour12: false,\n });\n clocks.push({ label, value, dateTime });\n }\n\n return clocks;\n}\n\n/**\n * A component to display a configurable list of clocks for various time zones.\n *\n * @example\n * Here's a simple example:\n * ```\n * // This will give you a clock for the time zone that Stockholm is in\n * // you can add more than one but keep in mind space may be limited\n * const clockConfigs: ClockConfig[] = [\n * {\n * label: 'STO',\n * timeZone: 'Europe/Stockholm',\n * },\n * ];\n *\n * // Setting hour12 to false will make all the clocks show in the 24hr format\n * const timeFormat: Intl.DateTimeFormatOptions = {\n * hour: '2-digit',\n * minute: '2-digit',\n * hour12: false,\n * };\n *\n * // Here is the component in use:\n * <HeaderWorldClock\n * clockConfigs={clockConfigs}\n * customTimeFormat={timeFormat}\n * />\n * ```\n *\n * @public\n */\nexport const HeaderWorldClock = (props: {\n clockConfigs: ClockConfig[];\n customTimeFormat?: Intl.DateTimeFormatOptions;\n}) => {\n const { clockConfigs, customTimeFormat } = props;\n\n const defaultTimes: TimeObj[] = [];\n const [clocks, setTimes] = React.useState(defaultTimes);\n\n React.useEffect(() => {\n setTimes(getTimes(clockConfigs, customTimeFormat));\n\n const intervalId = setInterval(() => {\n setTimes(getTimes(clockConfigs, customTimeFormat));\n }, 1000);\n\n return () => {\n clearInterval(intervalId);\n };\n }, [clockConfigs, customTimeFormat]);\n\n if (clocks.length !== 0) {\n return (\n <>\n {clocks.map(clock => (\n <HeaderLabel\n key={clock.label}\n label={clock.label}\n value={<time dateTime={clock.dateTime}>{clock.value}</time>}\n />\n ))}\n </>\n );\n }\n return null;\n};\n"],"names":[],"mappings":";;;AAmBA,MAAM,UAAyC,GAAA;AAAA,EAC7C,IAAM,EAAA,SAAA;AAAA,EACN,MAAQ,EAAA,SAAA;AACV,CAAA,CAAA;AAcA,SAAS,QAAA,CACP,cACA,gBACA,EAAA;AACA,EAAM,MAAA,CAAA,uBAAQ,IAAK,EAAA,CAAA;AACnB,EAAM,MAAA,IAAA,GAAO,OAAO,SAAU,CAAA,QAAA,CAAA;AAE9B,EAAA,MAAM,SAAoB,EAAC,CAAA;AAE3B,EAAA,IAAI,CAAC,YAAc,EAAA;AACjB,IAAO,OAAA,MAAA,CAAA;AAAA,GACT;AAEA,EAAA,KAAA,MAAW,eAAe,YAAc,EAAA;AACtC,IAAA,IAAI,QAAQ,WAAY,CAAA,KAAA,CAAA;AAExB,IAAA,MAAM,OAAsC,GAAA;AAAA,MAC1C,UAAU,WAAY,CAAA,QAAA;AAAA,MACtB,GAAI,gBAAoB,IAAA,
|
|
1
|
+
{"version":3,"file":"HeaderWorldClock.esm.js","sources":["../../../src/homePageComponents/HeaderWorldClock/HeaderWorldClock.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport { HeaderLabel } from '@backstage/core-components';\n\nconst timeFormat: Intl.DateTimeFormatOptions = {\n hour: '2-digit',\n minute: '2-digit',\n};\n\ntype TimeObj = {\n label: string;\n value: string;\n dateTime: string;\n};\n\n/** @public */\nexport type ClockConfig = {\n label: string;\n timeZone: string;\n};\n\nfunction getTimes(\n clockConfigs: ClockConfig[],\n customTimeFormat?: Intl.DateTimeFormatOptions,\n) {\n const d = new Date();\n const lang = window.navigator.language;\n\n const clocks: TimeObj[] = [];\n\n if (!clockConfigs) {\n return clocks;\n }\n\n for (const clockConfig of clockConfigs) {\n let label = clockConfig.label;\n\n const options: Intl.DateTimeFormatOptions = {\n timeZone: clockConfig.timeZone,\n ...(customTimeFormat ?? timeFormat),\n };\n\n try {\n new Date().toLocaleString(lang, options);\n } catch (e) {\n // eslint-disable-next-line no-console\n console.warn(\n `The timezone ${options.timeZone} is invalid. Defaulting to GMT`,\n );\n options.timeZone = 'GMT';\n label = 'GMT';\n }\n\n const value = d.toLocaleTimeString(lang, options);\n const dateTime = d.toLocaleTimeString(lang, {\n timeZone: options.timeZone,\n hour: '2-digit',\n minute: '2-digit',\n hour12: false,\n });\n clocks.push({ label, value, dateTime });\n }\n\n return clocks;\n}\n\n/**\n * A component to display a configurable list of clocks for various time zones.\n *\n * @example\n * Here's a simple example:\n * ```\n * // This will give you a clock for the time zone that Stockholm is in\n * // you can add more than one but keep in mind space may be limited\n * const clockConfigs: ClockConfig[] = [\n * {\n * label: 'STO',\n * timeZone: 'Europe/Stockholm',\n * },\n * ];\n *\n * // Setting hour12 to false will make all the clocks show in the 24hr format\n * const timeFormat: Intl.DateTimeFormatOptions = {\n * hour: '2-digit',\n * minute: '2-digit',\n * hour12: false,\n * };\n *\n * // Here is the component in use:\n * <HeaderWorldClock\n * clockConfigs={clockConfigs}\n * customTimeFormat={timeFormat}\n * />\n * ```\n *\n * @public\n */\nexport const HeaderWorldClock = (props: {\n clockConfigs: ClockConfig[];\n customTimeFormat?: Intl.DateTimeFormatOptions;\n}) => {\n const { clockConfigs, customTimeFormat } = props;\n\n const defaultTimes: TimeObj[] = [];\n const [clocks, setTimes] = React.useState(defaultTimes);\n\n React.useEffect(() => {\n setTimes(getTimes(clockConfigs, customTimeFormat));\n\n const intervalId = setInterval(() => {\n setTimes(getTimes(clockConfigs, customTimeFormat));\n }, 1000);\n\n return () => {\n clearInterval(intervalId);\n };\n }, [clockConfigs, customTimeFormat]);\n\n if (clocks.length !== 0) {\n return (\n <>\n {clocks.map(clock => (\n <HeaderLabel\n key={clock.label}\n label={clock.label}\n value={<time dateTime={clock.dateTime}>{clock.value}</time>}\n />\n ))}\n </>\n );\n }\n return null;\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -14,7 +14,6 @@ const Content = ({
|
|
|
14
14
|
noStarredEntitiesMessage,
|
|
15
15
|
groupByKind
|
|
16
16
|
}) => {
|
|
17
|
-
var _a, _b;
|
|
18
17
|
const catalogApi = useApi(catalogApiRef);
|
|
19
18
|
const { starredEntities, toggleStarredEntity } = useStarredEntities();
|
|
20
19
|
const [activeTab, setActiveTab] = React.useState(0);
|
|
@@ -38,7 +37,7 @@ const Content = ({
|
|
|
38
37
|
return /* @__PURE__ */ React.createElement(Progress, null);
|
|
39
38
|
}
|
|
40
39
|
const groupedEntities = {};
|
|
41
|
-
|
|
40
|
+
entities.value?.forEach((entity) => {
|
|
42
41
|
const kind = entity.kind;
|
|
43
42
|
if (!groupedEntities[kind]) {
|
|
44
43
|
groupedEntities[kind] = [];
|
|
@@ -46,13 +45,10 @@ const Content = ({
|
|
|
46
45
|
groupedEntities[kind].push(entity);
|
|
47
46
|
});
|
|
48
47
|
const groupByKindEntries = Object.entries(groupedEntities);
|
|
49
|
-
return entities.error ? /* @__PURE__ */ React.createElement(ResponseErrorPanel, { error: entities.error }) : /* @__PURE__ */ React.createElement("div", null, !groupByKind && /* @__PURE__ */ React.createElement(List, null,
|
|
50
|
-
(a, b) =>
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
(_b2 = b.metadata.title) != null ? _b2 : b.metadata.name
|
|
54
|
-
);
|
|
55
|
-
}
|
|
48
|
+
return entities.error ? /* @__PURE__ */ React.createElement(ResponseErrorPanel, { error: entities.error }) : /* @__PURE__ */ React.createElement("div", null, !groupByKind && /* @__PURE__ */ React.createElement(List, null, entities.value?.sort(
|
|
49
|
+
(a, b) => (a.metadata.title ?? a.metadata.name).localeCompare(
|
|
50
|
+
b.metadata.title ?? b.metadata.name
|
|
51
|
+
)
|
|
56
52
|
).map((entity) => /* @__PURE__ */ React.createElement(
|
|
57
53
|
StarredEntityListItem,
|
|
58
54
|
{
|
|
@@ -70,13 +66,10 @@ const Content = ({
|
|
|
70
66
|
"aria-label": "entity-tabs"
|
|
71
67
|
},
|
|
72
68
|
groupByKindEntries.map(([kind]) => /* @__PURE__ */ React.createElement(Tab, { key: kind, label: kind }))
|
|
73
|
-
), groupByKind && groupByKindEntries.map(([kind, entitiesByKind], index) => /* @__PURE__ */ React.createElement("div", { key: kind, hidden: groupByKind && activeTab !== index }, /* @__PURE__ */ React.createElement(List, null, entitiesByKind
|
|
74
|
-
(a, b) =>
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
(_b2 = b.metadata.title) != null ? _b2 : b.metadata.name
|
|
78
|
-
);
|
|
79
|
-
}
|
|
69
|
+
), groupByKind && groupByKindEntries.map(([kind, entitiesByKind], index) => /* @__PURE__ */ React.createElement("div", { key: kind, hidden: groupByKind && activeTab !== index }, /* @__PURE__ */ React.createElement(List, null, entitiesByKind?.sort(
|
|
70
|
+
(a, b) => (a.metadata.title ?? a.metadata.name).localeCompare(
|
|
71
|
+
b.metadata.title ?? b.metadata.name
|
|
72
|
+
)
|
|
80
73
|
).map((entity) => /* @__PURE__ */ React.createElement(
|
|
81
74
|
StarredEntityListItem,
|
|
82
75
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Content.esm.js","sources":["../../../src/homePageComponents/StarredEntities/Content.tsx"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n catalogApiRef,\n useStarredEntities,\n} from '@backstage/plugin-catalog-react';\nimport { Entity, stringifyEntityRef } from '@backstage/catalog-model';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { Progress, ResponseErrorPanel } from '@backstage/core-components';\nimport List from '@material-ui/core/List';\nimport Typography from '@material-ui/core/Typography';\nimport Tabs from '@material-ui/core/Tabs';\nimport Tab from '@material-ui/core/Tab';\nimport React from 'react';\nimport useAsync from 'react-use/esm/useAsync';\nimport { StarredEntityListItem } from '../../components/StarredEntityListItem/StarredEntityListItem';\n\n/**\n * A component to display a list of starred entities for the user.\n *\n * @public\n */\n\nexport type StarredEntitiesProps = {\n noStarredEntitiesMessage?: React.ReactNode | undefined;\n groupByKind?: boolean;\n};\n\nexport const Content = ({\n noStarredEntitiesMessage,\n groupByKind,\n}: StarredEntitiesProps) => {\n const catalogApi = useApi(catalogApiRef);\n const { starredEntities, toggleStarredEntity } = useStarredEntities();\n const [activeTab, setActiveTab] = React.useState(0);\n\n // Grab starred entities from catalog to ensure they still exist and also retrieve display titles\n const entities = useAsync(async () => {\n if (!starredEntities.size) {\n return [];\n }\n\n return (\n await catalogApi.getEntitiesByRefs({\n entityRefs: [...starredEntities],\n fields: [\n 'kind',\n 'metadata.namespace',\n 'metadata.name',\n 'metadata.title',\n ],\n })\n ).items.filter((e): e is Entity => !!e);\n }, [catalogApi, starredEntities]);\n\n if (starredEntities.size === 0)\n return (\n <Typography variant=\"body1\">\n {noStarredEntitiesMessage ||\n 'Click the star beside an entity name to add it to this list!'}\n </Typography>\n );\n\n if (entities.loading) {\n return <Progress />;\n }\n\n const groupedEntities: { [kind: string]: Entity[] } = {};\n entities.value?.forEach(entity => {\n const kind = entity.kind;\n if (!groupedEntities[kind]) {\n groupedEntities[kind] = [];\n }\n groupedEntities[kind].push(entity);\n });\n\n const groupByKindEntries = Object.entries(groupedEntities);\n\n return entities.error ? (\n <ResponseErrorPanel error={entities.error} />\n ) : (\n <div>\n {!groupByKind && (\n <List>\n {entities.value\n ?.sort((a, b) =>\n (a.metadata.title ?? a.metadata.name).localeCompare(\n b.metadata.title ?? b.metadata.name,\n ),\n )\n .map(entity => (\n <StarredEntityListItem\n key={stringifyEntityRef(entity)}\n entity={entity}\n onToggleStarredEntity={toggleStarredEntity}\n />\n ))}\n </List>\n )}\n\n {groupByKind && (\n <Tabs\n value={activeTab}\n onChange={(_, newValue) => setActiveTab(newValue)}\n variant=\"scrollable\"\n scrollButtons=\"auto\"\n aria-label=\"entity-tabs\"\n >\n {groupByKindEntries.map(([kind]) => (\n <Tab key={kind} label={kind} />\n ))}\n </Tabs>\n )}\n\n {groupByKind &&\n groupByKindEntries.map(([kind, entitiesByKind], index) => (\n <div key={kind} hidden={groupByKind && activeTab !== index}>\n <List>\n {entitiesByKind\n ?.sort((a, b) =>\n (a.metadata.title ?? a.metadata.name).localeCompare(\n b.metadata.title ?? b.metadata.name,\n ),\n )\n .map(entity => (\n <StarredEntityListItem\n key={stringifyEntityRef(entity)}\n entity={entity}\n onToggleStarredEntity={toggleStarredEntity}\n />\n ))}\n </List>\n </div>\n ))}\n </div>\n );\n};\n"],"names":[
|
|
1
|
+
{"version":3,"file":"Content.esm.js","sources":["../../../src/homePageComponents/StarredEntities/Content.tsx"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n catalogApiRef,\n useStarredEntities,\n} from '@backstage/plugin-catalog-react';\nimport { Entity, stringifyEntityRef } from '@backstage/catalog-model';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { Progress, ResponseErrorPanel } from '@backstage/core-components';\nimport List from '@material-ui/core/List';\nimport Typography from '@material-ui/core/Typography';\nimport Tabs from '@material-ui/core/Tabs';\nimport Tab from '@material-ui/core/Tab';\nimport React from 'react';\nimport useAsync from 'react-use/esm/useAsync';\nimport { StarredEntityListItem } from '../../components/StarredEntityListItem/StarredEntityListItem';\n\n/**\n * A component to display a list of starred entities for the user.\n *\n * @public\n */\n\nexport type StarredEntitiesProps = {\n noStarredEntitiesMessage?: React.ReactNode | undefined;\n groupByKind?: boolean;\n};\n\nexport const Content = ({\n noStarredEntitiesMessage,\n groupByKind,\n}: StarredEntitiesProps) => {\n const catalogApi = useApi(catalogApiRef);\n const { starredEntities, toggleStarredEntity } = useStarredEntities();\n const [activeTab, setActiveTab] = React.useState(0);\n\n // Grab starred entities from catalog to ensure they still exist and also retrieve display titles\n const entities = useAsync(async () => {\n if (!starredEntities.size) {\n return [];\n }\n\n return (\n await catalogApi.getEntitiesByRefs({\n entityRefs: [...starredEntities],\n fields: [\n 'kind',\n 'metadata.namespace',\n 'metadata.name',\n 'metadata.title',\n ],\n })\n ).items.filter((e): e is Entity => !!e);\n }, [catalogApi, starredEntities]);\n\n if (starredEntities.size === 0)\n return (\n <Typography variant=\"body1\">\n {noStarredEntitiesMessage ||\n 'Click the star beside an entity name to add it to this list!'}\n </Typography>\n );\n\n if (entities.loading) {\n return <Progress />;\n }\n\n const groupedEntities: { [kind: string]: Entity[] } = {};\n entities.value?.forEach(entity => {\n const kind = entity.kind;\n if (!groupedEntities[kind]) {\n groupedEntities[kind] = [];\n }\n groupedEntities[kind].push(entity);\n });\n\n const groupByKindEntries = Object.entries(groupedEntities);\n\n return entities.error ? (\n <ResponseErrorPanel error={entities.error} />\n ) : (\n <div>\n {!groupByKind && (\n <List>\n {entities.value\n ?.sort((a, b) =>\n (a.metadata.title ?? a.metadata.name).localeCompare(\n b.metadata.title ?? b.metadata.name,\n ),\n )\n .map(entity => (\n <StarredEntityListItem\n key={stringifyEntityRef(entity)}\n entity={entity}\n onToggleStarredEntity={toggleStarredEntity}\n />\n ))}\n </List>\n )}\n\n {groupByKind && (\n <Tabs\n value={activeTab}\n onChange={(_, newValue) => setActiveTab(newValue)}\n variant=\"scrollable\"\n scrollButtons=\"auto\"\n aria-label=\"entity-tabs\"\n >\n {groupByKindEntries.map(([kind]) => (\n <Tab key={kind} label={kind} />\n ))}\n </Tabs>\n )}\n\n {groupByKind &&\n groupByKindEntries.map(([kind, entitiesByKind], index) => (\n <div key={kind} hidden={groupByKind && activeTab !== index}>\n <List>\n {entitiesByKind\n ?.sort((a, b) =>\n (a.metadata.title ?? a.metadata.name).localeCompare(\n b.metadata.title ?? b.metadata.name,\n ),\n )\n .map(entity => (\n <StarredEntityListItem\n key={stringifyEntityRef(entity)}\n entity={entity}\n onToggleStarredEntity={toggleStarredEntity}\n />\n ))}\n </List>\n </div>\n ))}\n </div>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -34,10 +34,9 @@ const useStyles = makeStyles((theme) => ({
|
|
|
34
34
|
}
|
|
35
35
|
}));
|
|
36
36
|
const Content = (props) => {
|
|
37
|
-
var _a;
|
|
38
37
|
const classes = useStyles();
|
|
39
38
|
const toolkit = useToolkit();
|
|
40
|
-
const tools =
|
|
39
|
+
const tools = toolkit?.tools ?? props.tools;
|
|
41
40
|
return /* @__PURE__ */ React.createElement(List, { className: classes.toolkit }, tools.map((tool) => /* @__PURE__ */ React.createElement(Link, { key: tool.url, to: tool.url, className: classes.tool }, /* @__PURE__ */ React.createElement(ListItemIcon, { className: classes.icon }, tool.icon), /* @__PURE__ */ React.createElement(
|
|
42
41
|
ListItemText,
|
|
43
42
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Content.esm.js","sources":["../../../src/homePageComponents/Toolkit/Content.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Link } from '@backstage/core-components';\nimport List from '@material-ui/core/List';\nimport ListItemIcon from '@material-ui/core/ListItemIcon';\nimport ListItemText from '@material-ui/core/ListItemText';\nimport { makeStyles } from '@material-ui/core/styles';\nimport React from 'react';\nimport { useToolkit, Tool } from './Context';\n\nconst useStyles = makeStyles(theme => ({\n toolkit: {\n display: 'flex',\n flexWrap: 'wrap',\n textAlign: 'center',\n },\n tool: {\n margin: theme.spacing(0.5, 1),\n },\n label: {\n marginTop: theme.spacing(1),\n width: '72px',\n fontSize: '0.9em',\n lineHeight: '1.25',\n overflowWrap: 'break-word',\n color: theme.palette.text.secondary,\n },\n icon: {\n width: '64px',\n height: '64px',\n borderRadius: '50px',\n justifyContent: 'center',\n alignItems: 'center',\n boxShadow: theme.shadows[1],\n backgroundColor: theme.palette.background.default,\n },\n}));\n\n/**\n * A component to display a list of tools for the user.\n *\n * @public\n */\nexport const Content = (props: ToolkitContentProps) => {\n const classes = useStyles();\n const toolkit = useToolkit();\n const tools = toolkit?.tools ?? props.tools;\n\n return (\n <List className={classes.toolkit}>\n {tools.map((tool: Tool) => (\n <Link key={tool.url} to={tool.url} className={classes.tool}>\n <ListItemIcon className={classes.icon}>{tool.icon}</ListItemIcon>\n <ListItemText\n secondaryTypographyProps={{ className: classes.label }}\n secondary={tool.label}\n />\n </Link>\n ))}\n </List>\n );\n};\n\n/**\n * Props for Toolkit Content component.\n *\n * @public\n */\nexport type ToolkitContentProps = {\n tools: Tool[];\n};\n"],"names":[],"mappings":";;;;;;;;AAwBA,MAAM,SAAA,GAAY,WAAW,CAAU,KAAA,MAAA;AAAA,EACrC,OAAS,EAAA;AAAA,IACP,OAAS,EAAA,MAAA;AAAA,IACT,QAAU,EAAA,MAAA;AAAA,IACV,SAAW,EAAA,QAAA;AAAA,GACb;AAAA,EACA,IAAM,EAAA;AAAA,IACJ,MAAQ,EAAA,KAAA,CAAM,OAAQ,CAAA,GAAA,EAAK,CAAC,CAAA;AAAA,GAC9B;AAAA,EACA,KAAO,EAAA;AAAA,IACL,SAAA,EAAW,KAAM,CAAA,OAAA,CAAQ,CAAC,CAAA;AAAA,IAC1B,KAAO,EAAA,MAAA;AAAA,IACP,QAAU,EAAA,OAAA;AAAA,IACV,UAAY,EAAA,MAAA;AAAA,IACZ,YAAc,EAAA,YAAA;AAAA,IACd,KAAA,EAAO,KAAM,CAAA,OAAA,CAAQ,IAAK,CAAA,SAAA;AAAA,GAC5B;AAAA,EACA,IAAM,EAAA;AAAA,IACJ,KAAO,EAAA,MAAA;AAAA,IACP,MAAQ,EAAA,MAAA;AAAA,IACR,YAAc,EAAA,MAAA;AAAA,IACd,cAAgB,EAAA,QAAA;AAAA,IAChB,UAAY,EAAA,QAAA;AAAA,IACZ,SAAA,EAAW,KAAM,CAAA,OAAA,CAAQ,CAAC,CAAA;AAAA,IAC1B,eAAA,EAAiB,KAAM,CAAA,OAAA,CAAQ,UAAW,CAAA,OAAA;AAAA,GAC5C;AACF,CAAE,CAAA,CAAA,CAAA;AAOW,MAAA,OAAA,GAAU,CAAC,KAA+B,KAAA;
|
|
1
|
+
{"version":3,"file":"Content.esm.js","sources":["../../../src/homePageComponents/Toolkit/Content.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Link } from '@backstage/core-components';\nimport List from '@material-ui/core/List';\nimport ListItemIcon from '@material-ui/core/ListItemIcon';\nimport ListItemText from '@material-ui/core/ListItemText';\nimport { makeStyles } from '@material-ui/core/styles';\nimport React from 'react';\nimport { useToolkit, Tool } from './Context';\n\nconst useStyles = makeStyles(theme => ({\n toolkit: {\n display: 'flex',\n flexWrap: 'wrap',\n textAlign: 'center',\n },\n tool: {\n margin: theme.spacing(0.5, 1),\n },\n label: {\n marginTop: theme.spacing(1),\n width: '72px',\n fontSize: '0.9em',\n lineHeight: '1.25',\n overflowWrap: 'break-word',\n color: theme.palette.text.secondary,\n },\n icon: {\n width: '64px',\n height: '64px',\n borderRadius: '50px',\n justifyContent: 'center',\n alignItems: 'center',\n boxShadow: theme.shadows[1],\n backgroundColor: theme.palette.background.default,\n },\n}));\n\n/**\n * A component to display a list of tools for the user.\n *\n * @public\n */\nexport const Content = (props: ToolkitContentProps) => {\n const classes = useStyles();\n const toolkit = useToolkit();\n const tools = toolkit?.tools ?? props.tools;\n\n return (\n <List className={classes.toolkit}>\n {tools.map((tool: Tool) => (\n <Link key={tool.url} to={tool.url} className={classes.tool}>\n <ListItemIcon className={classes.icon}>{tool.icon}</ListItemIcon>\n <ListItemText\n secondaryTypographyProps={{ className: classes.label }}\n secondary={tool.label}\n />\n </Link>\n ))}\n </List>\n );\n};\n\n/**\n * Props for Toolkit Content component.\n *\n * @public\n */\nexport type ToolkitContentProps = {\n tools: Tool[];\n};\n"],"names":[],"mappings":";;;;;;;;AAwBA,MAAM,SAAA,GAAY,WAAW,CAAU,KAAA,MAAA;AAAA,EACrC,OAAS,EAAA;AAAA,IACP,OAAS,EAAA,MAAA;AAAA,IACT,QAAU,EAAA,MAAA;AAAA,IACV,SAAW,EAAA,QAAA;AAAA,GACb;AAAA,EACA,IAAM,EAAA;AAAA,IACJ,MAAQ,EAAA,KAAA,CAAM,OAAQ,CAAA,GAAA,EAAK,CAAC,CAAA;AAAA,GAC9B;AAAA,EACA,KAAO,EAAA;AAAA,IACL,SAAA,EAAW,KAAM,CAAA,OAAA,CAAQ,CAAC,CAAA;AAAA,IAC1B,KAAO,EAAA,MAAA;AAAA,IACP,QAAU,EAAA,OAAA;AAAA,IACV,UAAY,EAAA,MAAA;AAAA,IACZ,YAAc,EAAA,YAAA;AAAA,IACd,KAAA,EAAO,KAAM,CAAA,OAAA,CAAQ,IAAK,CAAA,SAAA;AAAA,GAC5B;AAAA,EACA,IAAM,EAAA;AAAA,IACJ,KAAO,EAAA,MAAA;AAAA,IACP,MAAQ,EAAA,MAAA;AAAA,IACR,YAAc,EAAA,MAAA;AAAA,IACd,cAAgB,EAAA,QAAA;AAAA,IAChB,UAAY,EAAA,QAAA;AAAA,IACZ,SAAA,EAAW,KAAM,CAAA,OAAA,CAAQ,CAAC,CAAA;AAAA,IAC1B,eAAA,EAAiB,KAAM,CAAA,OAAA,CAAQ,UAAW,CAAA,OAAA;AAAA,GAC5C;AACF,CAAE,CAAA,CAAA,CAAA;AAOW,MAAA,OAAA,GAAU,CAAC,KAA+B,KAAA;AACrD,EAAA,MAAM,UAAU,SAAU,EAAA,CAAA;AAC1B,EAAA,MAAM,UAAU,UAAW,EAAA,CAAA;AAC3B,EAAM,MAAA,KAAA,GAAQ,OAAS,EAAA,KAAA,IAAS,KAAM,CAAA,KAAA,CAAA;AAEtC,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,IAAK,EAAA,EAAA,SAAA,EAAW,OAAQ,CAAA,OAAA,EAAA,EACtB,KAAM,CAAA,GAAA,CAAI,CAAC,IAAA,qBACT,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,GAAK,EAAA,IAAA,CAAK,GAAK,EAAA,EAAA,EAAI,IAAK,CAAA,GAAA,EAAK,SAAW,EAAA,OAAA,CAAQ,IACpD,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,YAAa,EAAA,EAAA,SAAA,EAAW,OAAQ,CAAA,IAAA,EAAA,EAAO,IAAK,CAAA,IAAK,CAClD,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,YAAA;AAAA,IAAA;AAAA,MACC,wBAA0B,EAAA,EAAE,SAAW,EAAA,OAAA,CAAQ,KAAM,EAAA;AAAA,MACrD,WAAW,IAAK,CAAA,KAAA;AAAA,KAAA;AAAA,GAEpB,CACD,CACH,CAAA,CAAA;AAEJ;;;;"}
|
|
@@ -33,23 +33,22 @@ const Content = ({
|
|
|
33
33
|
const config = useApi(configApiRef);
|
|
34
34
|
const visitsApi = useApi(visitsApiRef);
|
|
35
35
|
const { loading: reqLoading } = useAsync(async () => {
|
|
36
|
-
var _a, _b;
|
|
37
36
|
if (!visits && !loading && kind === "recent") {
|
|
38
37
|
const filterBy = createFilterByQueryParamFromConfig(
|
|
39
|
-
|
|
38
|
+
config.getOptionalConfigArray("home.recentVisits.filterBy") ?? []
|
|
40
39
|
);
|
|
41
40
|
return await visitsApi.list({
|
|
42
|
-
limit: numVisitsTotal
|
|
41
|
+
limit: numVisitsTotal ?? 8,
|
|
43
42
|
orderBy: [{ field: "timestamp", direction: "desc" }],
|
|
44
43
|
...filterBy && { filterBy }
|
|
45
44
|
}).then(setVisits);
|
|
46
45
|
}
|
|
47
46
|
if (!visits && !loading && kind === "top") {
|
|
48
47
|
const filterBy = createFilterByQueryParamFromConfig(
|
|
49
|
-
|
|
48
|
+
config.getOptionalConfigArray("home.topVisits.filterBy") ?? []
|
|
50
49
|
);
|
|
51
50
|
return await visitsApi.list({
|
|
52
|
-
limit: numVisitsTotal
|
|
51
|
+
limit: numVisitsTotal ?? 8,
|
|
53
52
|
orderBy: [{ field: "hits", direction: "desc" }],
|
|
54
53
|
...filterBy && { filterBy }
|
|
55
54
|
}).then(setVisits);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Content.esm.js","sources":["../../../src/homePageComponents/VisitedByType/Content.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useEffect } from 'react';\nimport { createFilterByQueryParamFromConfig } from '../../api/config';\nimport { VisitedByType } from './VisitedByType';\nimport { Visit, visitsApiRef } from '../../api';\nimport { ContextValueOnly, useContext } from './Context';\nimport { configApiRef, useApi } from '@backstage/core-plugin-api';\nimport useAsync from 'react-use/esm/useAsync';\n\n/** @public */\nexport type VisitedByTypeKind = 'recent' | 'top';\n\n/** @public */\nexport type VisitedByTypeProps = {\n visits?: Array<Visit>;\n numVisitsOpen?: number;\n numVisitsTotal?: number;\n loading?: boolean;\n kind: VisitedByTypeKind;\n};\n\n/**\n * Display recently visited pages for the homepage\n * @public\n */\nexport const Content = ({\n visits,\n numVisitsOpen,\n numVisitsTotal,\n loading,\n kind,\n}: VisitedByTypeProps) => {\n const { setContext, setVisits, setLoading } = useContext();\n // Allows behavior override from properties\n useEffect(() => {\n const context: Partial<ContextValueOnly> = {};\n context.kind = kind;\n if (visits) {\n context.visits = visits;\n context.loading = false;\n } else if (loading) {\n context.loading = loading;\n }\n if (numVisitsOpen) context.numVisitsOpen = numVisitsOpen;\n if (numVisitsTotal) context.numVisitsTotal = numVisitsTotal;\n setContext(state => ({ ...state, ...context }));\n }, [setContext, kind, visits, loading, numVisitsOpen, numVisitsTotal]);\n\n const config = useApi(configApiRef);\n // Fetches data from visitsApi in case visits and loading are not provided\n const visitsApi = useApi(visitsApiRef);\n const { loading: reqLoading } = useAsync(async () => {\n if (!visits && !loading && kind === 'recent') {\n const filterBy = createFilterByQueryParamFromConfig(\n config.getOptionalConfigArray('home.recentVisits.filterBy') ?? [],\n );\n return await visitsApi\n .list({\n limit: numVisitsTotal ?? 8,\n orderBy: [{ field: 'timestamp', direction: 'desc' }],\n ...(filterBy && { filterBy }),\n })\n .then(setVisits);\n }\n if (!visits && !loading && kind === 'top') {\n const filterBy = createFilterByQueryParamFromConfig(\n config.getOptionalConfigArray('home.topVisits.filterBy') ?? [],\n );\n return await visitsApi\n .list({\n limit: numVisitsTotal ?? 8,\n orderBy: [{ field: 'hits', direction: 'desc' }],\n ...(filterBy && { filterBy }),\n })\n .then(setVisits);\n }\n return undefined;\n }, [visitsApi, visits, loading, setVisits]);\n useEffect(() => {\n if (!loading) {\n setLoading(reqLoading);\n }\n }, [loading, setLoading, reqLoading]);\n\n return <VisitedByType />;\n};\n"],"names":[],"mappings":";;;;;;;;;AAwCO,MAAM,UAAU,CAAC;AAAA,EACtB,MAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,OAAA;AAAA,EACA,IAAA;AACF,CAA0B,KAAA;AACxB,EAAA,MAAM,EAAE,UAAA,EAAY,SAAW,EAAA,UAAA,KAAe,UAAW,EAAA,CAAA;AAEzD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,UAAqC,EAAC,CAAA;AAC5C,IAAA,OAAA,CAAQ,IAAO,GAAA,IAAA,CAAA;AACf,IAAA,IAAI,MAAQ,EAAA;AACV,MAAA,OAAA,CAAQ,MAAS,GAAA,MAAA,CAAA;AACjB,MAAA,OAAA,CAAQ,OAAU,GAAA,KAAA,CAAA;AAAA,eACT,OAAS,EAAA;AAClB,MAAA,OAAA,CAAQ,OAAU,GAAA,OAAA,CAAA;AAAA,KACpB;AACA,IAAI,IAAA,aAAA;AAAe,MAAA,OAAA,CAAQ,aAAgB,GAAA,aAAA,CAAA;AAC3C,IAAI,IAAA,cAAA;AAAgB,MAAA,OAAA,CAAQ,cAAiB,GAAA,cAAA,CAAA;AAC7C,IAAA,UAAA,CAAW,YAAU,EAAE,GAAG,KAAO,EAAA,GAAG,SAAU,CAAA,CAAA,CAAA;AAAA,GAChD,EAAG,CAAC,UAAY,EAAA,IAAA,EAAM,QAAQ,OAAS,EAAA,aAAA,EAAe,cAAc,CAAC,CAAA,CAAA;AAErE,EAAM,MAAA,MAAA,GAAS,OAAO,YAAY,CAAA,CAAA;AAElC,EAAM,MAAA,SAAA,GAAY,OAAO,YAAY,CAAA,CAAA;AACrC,EAAA,MAAM,EAAE,OAAA,EAAS,UAAW,EAAA,GAAI,SAAS,YAAY;
|
|
1
|
+
{"version":3,"file":"Content.esm.js","sources":["../../../src/homePageComponents/VisitedByType/Content.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useEffect } from 'react';\nimport { createFilterByQueryParamFromConfig } from '../../api/config';\nimport { VisitedByType } from './VisitedByType';\nimport { Visit, visitsApiRef } from '../../api';\nimport { ContextValueOnly, useContext } from './Context';\nimport { configApiRef, useApi } from '@backstage/core-plugin-api';\nimport useAsync from 'react-use/esm/useAsync';\n\n/** @public */\nexport type VisitedByTypeKind = 'recent' | 'top';\n\n/** @public */\nexport type VisitedByTypeProps = {\n visits?: Array<Visit>;\n numVisitsOpen?: number;\n numVisitsTotal?: number;\n loading?: boolean;\n kind: VisitedByTypeKind;\n};\n\n/**\n * Display recently visited pages for the homepage\n * @public\n */\nexport const Content = ({\n visits,\n numVisitsOpen,\n numVisitsTotal,\n loading,\n kind,\n}: VisitedByTypeProps) => {\n const { setContext, setVisits, setLoading } = useContext();\n // Allows behavior override from properties\n useEffect(() => {\n const context: Partial<ContextValueOnly> = {};\n context.kind = kind;\n if (visits) {\n context.visits = visits;\n context.loading = false;\n } else if (loading) {\n context.loading = loading;\n }\n if (numVisitsOpen) context.numVisitsOpen = numVisitsOpen;\n if (numVisitsTotal) context.numVisitsTotal = numVisitsTotal;\n setContext(state => ({ ...state, ...context }));\n }, [setContext, kind, visits, loading, numVisitsOpen, numVisitsTotal]);\n\n const config = useApi(configApiRef);\n // Fetches data from visitsApi in case visits and loading are not provided\n const visitsApi = useApi(visitsApiRef);\n const { loading: reqLoading } = useAsync(async () => {\n if (!visits && !loading && kind === 'recent') {\n const filterBy = createFilterByQueryParamFromConfig(\n config.getOptionalConfigArray('home.recentVisits.filterBy') ?? [],\n );\n return await visitsApi\n .list({\n limit: numVisitsTotal ?? 8,\n orderBy: [{ field: 'timestamp', direction: 'desc' }],\n ...(filterBy && { filterBy }),\n })\n .then(setVisits);\n }\n if (!visits && !loading && kind === 'top') {\n const filterBy = createFilterByQueryParamFromConfig(\n config.getOptionalConfigArray('home.topVisits.filterBy') ?? [],\n );\n return await visitsApi\n .list({\n limit: numVisitsTotal ?? 8,\n orderBy: [{ field: 'hits', direction: 'desc' }],\n ...(filterBy && { filterBy }),\n })\n .then(setVisits);\n }\n return undefined;\n }, [visitsApi, visits, loading, setVisits]);\n useEffect(() => {\n if (!loading) {\n setLoading(reqLoading);\n }\n }, [loading, setLoading, reqLoading]);\n\n return <VisitedByType />;\n};\n"],"names":[],"mappings":";;;;;;;;;AAwCO,MAAM,UAAU,CAAC;AAAA,EACtB,MAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,OAAA;AAAA,EACA,IAAA;AACF,CAA0B,KAAA;AACxB,EAAA,MAAM,EAAE,UAAA,EAAY,SAAW,EAAA,UAAA,KAAe,UAAW,EAAA,CAAA;AAEzD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,UAAqC,EAAC,CAAA;AAC5C,IAAA,OAAA,CAAQ,IAAO,GAAA,IAAA,CAAA;AACf,IAAA,IAAI,MAAQ,EAAA;AACV,MAAA,OAAA,CAAQ,MAAS,GAAA,MAAA,CAAA;AACjB,MAAA,OAAA,CAAQ,OAAU,GAAA,KAAA,CAAA;AAAA,eACT,OAAS,EAAA;AAClB,MAAA,OAAA,CAAQ,OAAU,GAAA,OAAA,CAAA;AAAA,KACpB;AACA,IAAI,IAAA,aAAA;AAAe,MAAA,OAAA,CAAQ,aAAgB,GAAA,aAAA,CAAA;AAC3C,IAAI,IAAA,cAAA;AAAgB,MAAA,OAAA,CAAQ,cAAiB,GAAA,cAAA,CAAA;AAC7C,IAAA,UAAA,CAAW,YAAU,EAAE,GAAG,KAAO,EAAA,GAAG,SAAU,CAAA,CAAA,CAAA;AAAA,GAChD,EAAG,CAAC,UAAY,EAAA,IAAA,EAAM,QAAQ,OAAS,EAAA,aAAA,EAAe,cAAc,CAAC,CAAA,CAAA;AAErE,EAAM,MAAA,MAAA,GAAS,OAAO,YAAY,CAAA,CAAA;AAElC,EAAM,MAAA,SAAA,GAAY,OAAO,YAAY,CAAA,CAAA;AACrC,EAAA,MAAM,EAAE,OAAA,EAAS,UAAW,EAAA,GAAI,SAAS,YAAY;AACnD,IAAA,IAAI,CAAC,MAAA,IAAU,CAAC,OAAA,IAAW,SAAS,QAAU,EAAA;AAC5C,MAAA,MAAM,QAAW,GAAA,kCAAA;AAAA,QACf,MAAO,CAAA,sBAAA,CAAuB,4BAA4B,CAAA,IAAK,EAAC;AAAA,OAClE,CAAA;AACA,MAAO,OAAA,MAAM,UACV,IAAK,CAAA;AAAA,QACJ,OAAO,cAAkB,IAAA,CAAA;AAAA,QACzB,SAAS,CAAC,EAAE,OAAO,WAAa,EAAA,SAAA,EAAW,QAAQ,CAAA;AAAA,QACnD,GAAI,QAAY,IAAA,EAAE,QAAS,EAAA;AAAA,OAC5B,CACA,CAAA,IAAA,CAAK,SAAS,CAAA,CAAA;AAAA,KACnB;AACA,IAAA,IAAI,CAAC,MAAA,IAAU,CAAC,OAAA,IAAW,SAAS,KAAO,EAAA;AACzC,MAAA,MAAM,QAAW,GAAA,kCAAA;AAAA,QACf,MAAO,CAAA,sBAAA,CAAuB,yBAAyB,CAAA,IAAK,EAAC;AAAA,OAC/D,CAAA;AACA,MAAO,OAAA,MAAM,UACV,IAAK,CAAA;AAAA,QACJ,OAAO,cAAkB,IAAA,CAAA;AAAA,QACzB,SAAS,CAAC,EAAE,OAAO,MAAQ,EAAA,SAAA,EAAW,QAAQ,CAAA;AAAA,QAC9C,GAAI,QAAY,IAAA,EAAE,QAAS,EAAA;AAAA,OAC5B,CACA,CAAA,IAAA,CAAK,SAAS,CAAA,CAAA;AAAA,KACnB;AACA,IAAO,OAAA,KAAA,CAAA,CAAA;AAAA,KACN,CAAC,SAAA,EAAW,MAAQ,EAAA,OAAA,EAAS,SAAS,CAAC,CAAA,CAAA;AAC1C,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,OAAS,EAAA;AACZ,MAAA,UAAA,CAAW,UAAU,CAAA,CAAA;AAAA,KACvB;AAAA,GACC,EAAA,CAAC,OAAS,EAAA,UAAA,EAAY,UAAU,CAAC,CAAA,CAAA;AAEpC,EAAA,2CAAQ,aAAc,EAAA,IAAA,CAAA,CAAA;AACxB;;;;"}
|
|
@@ -20,7 +20,7 @@ const WelcomeTitle = ({ language }) => {
|
|
|
20
20
|
});
|
|
21
21
|
}
|
|
22
22
|
}, [error, alertApi]);
|
|
23
|
-
return /* @__PURE__ */ React.createElement(Tooltip, { title: greeting.language }, /* @__PURE__ */ React.createElement(Typography, { component: "span", variant: "inherit" }, `${greeting.greeting}${
|
|
23
|
+
return /* @__PURE__ */ React.createElement(Tooltip, { title: greeting.language }, /* @__PURE__ */ React.createElement(Typography, { component: "span", variant: "inherit" }, `${greeting.greeting}${profile?.displayName ? `, ${profile?.displayName}` : ""}!`));
|
|
24
24
|
};
|
|
25
25
|
|
|
26
26
|
export { WelcomeTitle };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WelcomeTitle.esm.js","sources":["../../../src/homePageComponents/WelcomeTitle/WelcomeTitle.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n alertApiRef,\n identityApiRef,\n useApi,\n} from '@backstage/core-plugin-api';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport Typography from '@material-ui/core/Typography';\nimport React, { useEffect, useMemo } from 'react';\nimport useAsync from 'react-use/esm/useAsync';\nimport { getTimeBasedGreeting } from './timeUtil';\n\n/** @public */\nexport type WelcomeTitleLanguageProps = {\n language?: string[];\n};\n\nexport const WelcomeTitle = ({ language }: WelcomeTitleLanguageProps) => {\n const identityApi = useApi(identityApiRef);\n const alertApi = useApi(alertApiRef);\n const greeting = useMemo(() => getTimeBasedGreeting(language), [language]);\n\n const { value: profile, error } = useAsync(() =>\n identityApi.getProfileInfo(),\n );\n\n useEffect(() => {\n if (error) {\n alertApi.post({\n message: `Failed to load user identity: ${error}`,\n severity: 'error',\n });\n }\n }, [error, alertApi]);\n\n return (\n <Tooltip title={greeting.language}>\n <Typography component=\"span\" variant=\"inherit\">{`${greeting.greeting}${\n profile?.displayName ? `, ${profile?.displayName}` : ''\n }!`}</Typography>\n </Tooltip>\n );\n};\n"],"names":[],"mappings":";;;;;;;AA+BO,MAAM,YAAe,GAAA,CAAC,EAAE,QAAA,EAA0C,KAAA;AACvE,EAAM,MAAA,WAAA,GAAc,OAAO,cAAc,CAAA,CAAA;AACzC,EAAM,MAAA,QAAA,GAAW,OAAO,WAAW,CAAA,CAAA;AACnC,EAAM,MAAA,QAAA,GAAW,QAAQ,MAAM,oBAAA,CAAqB,QAAQ,CAAG,EAAA,CAAC,QAAQ,CAAC,CAAA,CAAA;AAEzE,EAAA,MAAM,EAAE,KAAA,EAAO,OAAS,EAAA,KAAA,EAAU,GAAA,QAAA;AAAA,IAAS,MACzC,YAAY,cAAe,EAAA;AAAA,GAC7B,CAAA;AAEA,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,KAAO,EAAA;AACT,MAAA,QAAA,CAAS,IAAK,CAAA;AAAA,QACZ,OAAA,EAAS,iCAAiC,KAAK,CAAA,CAAA;AAAA,QAC/C,QAAU,EAAA,OAAA;AAAA,OACX,CAAA,CAAA;AAAA,KACH;AAAA,GACC,EAAA,CAAC,KAAO,EAAA,QAAQ,CAAC,CAAA,CAAA;AAEpB,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,WAAQ,KAAO,EAAA,QAAA,CAAS,4BACtB,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,SAAU,EAAA,MAAA,EAAO,OAAQ,EAAA,SAAA,EAAA,EAAW,GAAG,QAAS,CAAA,QAAQ,CAClE,EAAA,
|
|
1
|
+
{"version":3,"file":"WelcomeTitle.esm.js","sources":["../../../src/homePageComponents/WelcomeTitle/WelcomeTitle.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n alertApiRef,\n identityApiRef,\n useApi,\n} from '@backstage/core-plugin-api';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport Typography from '@material-ui/core/Typography';\nimport React, { useEffect, useMemo } from 'react';\nimport useAsync from 'react-use/esm/useAsync';\nimport { getTimeBasedGreeting } from './timeUtil';\n\n/** @public */\nexport type WelcomeTitleLanguageProps = {\n language?: string[];\n};\n\nexport const WelcomeTitle = ({ language }: WelcomeTitleLanguageProps) => {\n const identityApi = useApi(identityApiRef);\n const alertApi = useApi(alertApiRef);\n const greeting = useMemo(() => getTimeBasedGreeting(language), [language]);\n\n const { value: profile, error } = useAsync(() =>\n identityApi.getProfileInfo(),\n );\n\n useEffect(() => {\n if (error) {\n alertApi.post({\n message: `Failed to load user identity: ${error}`,\n severity: 'error',\n });\n }\n }, [error, alertApi]);\n\n return (\n <Tooltip title={greeting.language}>\n <Typography component=\"span\" variant=\"inherit\">{`${greeting.greeting}${\n profile?.displayName ? `, ${profile?.displayName}` : ''\n }!`}</Typography>\n </Tooltip>\n );\n};\n"],"names":[],"mappings":";;;;;;;AA+BO,MAAM,YAAe,GAAA,CAAC,EAAE,QAAA,EAA0C,KAAA;AACvE,EAAM,MAAA,WAAA,GAAc,OAAO,cAAc,CAAA,CAAA;AACzC,EAAM,MAAA,QAAA,GAAW,OAAO,WAAW,CAAA,CAAA;AACnC,EAAM,MAAA,QAAA,GAAW,QAAQ,MAAM,oBAAA,CAAqB,QAAQ,CAAG,EAAA,CAAC,QAAQ,CAAC,CAAA,CAAA;AAEzE,EAAA,MAAM,EAAE,KAAA,EAAO,OAAS,EAAA,KAAA,EAAU,GAAA,QAAA;AAAA,IAAS,MACzC,YAAY,cAAe,EAAA;AAAA,GAC7B,CAAA;AAEA,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,KAAO,EAAA;AACT,MAAA,QAAA,CAAS,IAAK,CAAA;AAAA,QACZ,OAAA,EAAS,iCAAiC,KAAK,CAAA,CAAA;AAAA,QAC/C,QAAU,EAAA,OAAA;AAAA,OACX,CAAA,CAAA;AAAA,KACH;AAAA,GACC,EAAA,CAAC,KAAO,EAAA,QAAQ,CAAC,CAAA,CAAA;AAEpB,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,WAAQ,KAAO,EAAA,QAAA,CAAS,4BACtB,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,SAAU,EAAA,MAAA,EAAO,OAAQ,EAAA,SAAA,EAAA,EAAW,GAAG,QAAS,CAAA,QAAQ,CAClE,EAAA,OAAA,EAAS,WAAc,GAAA,CAAA,EAAA,EAAK,SAAS,WAAW,CAAA,CAAA,GAAK,EACvD,CAAA,CAAA,CAAI,CACN,CAAA,CAAA;AAEJ;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/plugin-home",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.5-next.0",
|
|
4
4
|
"description": "A Backstage plugin that helps you build a home page",
|
|
5
5
|
"backstage": {
|
|
6
6
|
"role": "frontend-plugin"
|
|
@@ -54,13 +54,13 @@
|
|
|
54
54
|
"@backstage/catalog-model": "^1.5.0",
|
|
55
55
|
"@backstage/config": "^1.2.0",
|
|
56
56
|
"@backstage/core-app-api": "^1.12.5",
|
|
57
|
-
"@backstage/core-compat-api": "^0.2.
|
|
58
|
-
"@backstage/core-components": "^0.14.
|
|
57
|
+
"@backstage/core-compat-api": "^0.2.6-next.0",
|
|
58
|
+
"@backstage/core-components": "^0.14.8-next.0",
|
|
59
59
|
"@backstage/core-plugin-api": "^1.9.2",
|
|
60
|
-
"@backstage/frontend-plugin-api": "^0.6.
|
|
61
|
-
"@backstage/plugin-catalog-react": "^1.12.0",
|
|
62
|
-
"@backstage/plugin-home-react": "^0.1.
|
|
63
|
-
"@backstage/theme": "^0.5.
|
|
60
|
+
"@backstage/frontend-plugin-api": "^0.6.6-next.0",
|
|
61
|
+
"@backstage/plugin-catalog-react": "^1.12.1-next.0",
|
|
62
|
+
"@backstage/plugin-home-react": "^0.1.14-next.0",
|
|
63
|
+
"@backstage/theme": "^0.5.6-next.0",
|
|
64
64
|
"@material-ui/core": "^4.12.2",
|
|
65
65
|
"@material-ui/icons": "^4.9.1",
|
|
66
66
|
"@material-ui/lab": "4.0.0-alpha.61",
|
|
@@ -77,9 +77,9 @@
|
|
|
77
77
|
"zod": "^3.22.4"
|
|
78
78
|
},
|
|
79
79
|
"devDependencies": {
|
|
80
|
-
"@backstage/cli": "^0.26.
|
|
81
|
-
"@backstage/dev-utils": "^1.0.
|
|
82
|
-
"@backstage/test-utils": "^1.5.
|
|
80
|
+
"@backstage/cli": "^0.26.6-next.0",
|
|
81
|
+
"@backstage/dev-utils": "^1.0.33-next.0",
|
|
82
|
+
"@backstage/test-utils": "^1.5.6-next.0",
|
|
83
83
|
"@testing-library/dom": "^10.0.0",
|
|
84
84
|
"@testing-library/jest-dom": "^6.0.0",
|
|
85
85
|
"@testing-library/react": "^15.0.0",
|