@spotify/backstage-plugin-soundcheck 0.7.0 → 0.8.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 +56 -0
- package/README.md +132 -7
- package/dist/esm/{EntitySoundcheckContent-52a2a214.esm.js → EntitySoundcheckContent-592fa779.esm.js} +2 -2
- package/dist/esm/OverviewPageContent-7cf86a3a.esm.js +2 -0
- package/dist/esm/{RefetchingIndicator-7160bb11.esm.js → RefetchingIndicator-b042ec49.esm.js} +2 -2
- package/dist/esm/index-100619e3.esm.js +2 -0
- package/dist/esm/{index-0024f6e1.esm.js → index-540b325c.esm.js} +2 -2
- package/dist/esm/index-95ae147b.esm.js +388 -0
- package/dist/esm/{index-829d0670.esm.js → index-fcd50c7d.esm.js} +2 -2
- package/dist/index.esm.js +1 -1
- package/package.json +23 -17
- package/dist/esm/OverviewPageContent-dbbba0be.esm.js +0 -2
- package/dist/esm/index-37aedac7.esm.js +0 -299
- package/dist/esm/index-c29fd0e9.esm.js +0 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,61 @@
|
|
|
1
1
|
# @spotify/backstage-plugin-soundcheck
|
|
2
2
|
|
|
3
|
+
## 0.8.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- The GitHub fact collector can now be configured through the Soundcheck UI.
|
|
8
|
+
- Soundcheck now includes a Tech Health page that provides filterable, aggregate metrics over Soundcheck
|
|
9
|
+
data. This new Tech Health page provides five tabbed pages and a global filter. Each tab enables
|
|
10
|
+
users to view aggregate Soundcheck data from a distinct viewpoint.
|
|
11
|
+
|
|
12
|
+
- **The Summary Tab**: This tab shows the overall check pass rate, track pass rate, entity pass rate,
|
|
13
|
+
and team pass rate, both currently and over time.
|
|
14
|
+
|
|
15
|
+
- **The Checks Tab**: This tab shows the overall pass rate for individual Soundcheck checks, allowing
|
|
16
|
+
users to see at a glance how a particular check or set of checks is performing both now and over time.
|
|
17
|
+
|
|
18
|
+
- **The Tracks Tab**: This tab shows the overall pass rate for individual Soundcheck Tracks, allowing
|
|
19
|
+
users to easily understand how a particular Track or set of Tracks is performing now and over time.
|
|
20
|
+
|
|
21
|
+
- **The Entities Tab**: This tab shows the overall pass rate of the entities in the software catalog,
|
|
22
|
+
allowing users to quickly see how entities in their system are performing relative to the checks that
|
|
23
|
+
Soundcheck is performing.
|
|
24
|
+
|
|
25
|
+
- **The Teams Tab**: Finally, this tab shows the aggregate performance of groups of entities organized
|
|
26
|
+
by team ownership relative to those Soundcheck checks that apply to each team's components.
|
|
27
|
+
|
|
28
|
+
- **The Global Filter**: All Tech Health tabs share a common filter component, which is used to narrow the scope
|
|
29
|
+
of displayed data across all Tech Health tabs. The global filter is composed of the following intuitive
|
|
30
|
+
sub-filters:
|
|
31
|
+
|
|
32
|
+
- Days: Filters historical data by a number of days.
|
|
33
|
+
- Entity (software component) Filter: Aggregate data will only pertain to those entities selected in this filter.
|
|
34
|
+
- Entity Owners: Aggregate data will only pertain to those entities owned by the selected owners.
|
|
35
|
+
- Tracks: Aggregate data will only pertain to those tracks selected in this filter.
|
|
36
|
+
- Track Levels: Aggregate data will only pertain to those track levels selected in this filter.
|
|
37
|
+
- Checks: Aggregate data will only pertain to those checks selected in this filter.
|
|
38
|
+
- Check Owners: Aggregate data will pertain only to the set of checks owned by all check owners selected in this filter.
|
|
39
|
+
|
|
40
|
+
### Patch Changes
|
|
41
|
+
|
|
42
|
+
- Mark package as being free of side effects, allowing more optimized Webpack builds.
|
|
43
|
+
- The delete icon is no longer displayed beside the first rule of the Check form.
|
|
44
|
+
- Updated dependency `recharts` to `^2.8.0`.
|
|
45
|
+
- Updated dependency `@testing-library/jest-dom` to `^6.0.0`.
|
|
46
|
+
- Upgraded Backstage to v1.18.1
|
|
47
|
+
- Resolved an issue where changing Fact was not clearing the Path/Operator/Value fields in the Check UI.
|
|
48
|
+
- Resolved an issue where newly added Checks would not immediately show up in the Track UI.
|
|
49
|
+
- Resolved an issue where the text for warning messages on the Soundcheck Group page was not accurate.
|
|
50
|
+
- Tooltips in the overview table now support Markdown in check descriptions.
|
|
51
|
+
- Updated dependencies
|
|
52
|
+
- Updated dependencies
|
|
53
|
+
- Updated dependencies
|
|
54
|
+
- Updated dependencies
|
|
55
|
+
- Updated dependencies
|
|
56
|
+
- @spotify/backstage-plugin-soundcheck-common@0.8.0
|
|
57
|
+
- @spotify/backstage-plugin-core@0.5.6
|
|
58
|
+
|
|
3
59
|
## 0.7.0
|
|
4
60
|
|
|
5
61
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -9,11 +9,44 @@ There are 5 fundamental elements that make up Soundcheck:
|
|
|
9
9
|
- **Check**: A standard or best practice a component is graded against.
|
|
10
10
|
- **Check Result**: The result of running a check against a component. Results are either pass or fail.
|
|
11
11
|
- **Track**: A long-term tech health initiative.
|
|
12
|
-
- **Level**: A group of checks that represent a milestone within a
|
|
12
|
+
- **Level**: A group of checks that represent a milestone within a track.
|
|
13
13
|
- **Certification**: The outcome of passing all checks within a level.
|
|
14
14
|
|
|
15
15
|
Together, they show you how any given software component is performing against your organization's long-term tech health initiatives.
|
|
16
16
|
|
|
17
|
+
<!-- TOC -->
|
|
18
|
+
|
|
19
|
+
- [Spotify Plugins for Backstage: Soundcheck](#spotify-plugins-for-backstage-soundcheck)
|
|
20
|
+
- [Prerequisites](#prerequisites)
|
|
21
|
+
- [1. Install the Soundcheck backend plugin](#1-install-the-soundcheck-backend-plugin)
|
|
22
|
+
- [Installation](#installation)
|
|
23
|
+
- [1. Install the plugin](#1-install-the-plugin)
|
|
24
|
+
- [2. Install Soundcheck Entity Content Page & Card](#2-install-soundcheck-entity-content-page--card)
|
|
25
|
+
- [3. Install Soundcheck Routing Page](#3-install-soundcheck-routing-page)
|
|
26
|
+
- [4. Setup sidebar item](#4-setup-sidebar-item)
|
|
27
|
+
- [5. Install Soundcheck Group Content Page](#5-install-soundcheck-group-content-page)
|
|
28
|
+
- [6. Check everything is working](#6-check-everything-is-working)
|
|
29
|
+
- [Product Documentation](#product-documentation)
|
|
30
|
+
- [No-Code UI for checks, tracks and facts management](#no-code-ui-for-checks-tracks-and-facts-management)
|
|
31
|
+
- [Using the No-Code UI](#using-the-no-code-ui)
|
|
32
|
+
- [Checks](#checks)
|
|
33
|
+
- [Creating a new check](#creating-a-new-check)
|
|
34
|
+
- [Editing a check](#editing-a-check)
|
|
35
|
+
- [Tracks](#tracks)
|
|
36
|
+
- [Creating a new track](#creating-a-new-track)
|
|
37
|
+
- [Editing a track](#editing-a-track)
|
|
38
|
+
- [Fact Collectors](#fact-collectors)
|
|
39
|
+
- [Configuring a fact collector](#configuring-a-fact-collector)
|
|
40
|
+
- [Frequency](#frequency)
|
|
41
|
+
- [Filters](#filters)
|
|
42
|
+
- [Caching](#caching)
|
|
43
|
+
- [RBAC Integration](#rbac-integration)
|
|
44
|
+
- [Soundcheck Tech Health Page](#soundcheck-tech-health-page)
|
|
45
|
+
- [Aggregations](#aggregations)
|
|
46
|
+
- [Filters](#filters-1)
|
|
47
|
+
- [Trends](#trends)
|
|
48
|
+
<!-- TOC -->
|
|
49
|
+
|
|
17
50
|
## Prerequisites
|
|
18
51
|
|
|
19
52
|
### 1. Install the Soundcheck backend plugin
|
|
@@ -157,20 +190,20 @@ const groupPage = (
|
|
|
157
190
|
### 6. Check everything is working
|
|
158
191
|
|
|
159
192
|
If you have followed all steps up to this point, Soundcheck is set up and
|
|
160
|
-
running. The backend successfully starts up if the
|
|
193
|
+
running. The backend successfully starts up if the track config is valid, and
|
|
161
194
|
when you navigate to a catalog page for one of the entity types you configured
|
|
162
|
-
above, you'll see the Soundcheck tab containing the applicable
|
|
195
|
+
above, you'll see the Soundcheck tab containing the applicable tracks for the
|
|
163
196
|
current entity. If you visit `/soundcheck` or click the "Soundcheck" entry on the sidebar, you should see the overview page.
|
|
164
197
|
|
|
165
198
|
# Product Documentation
|
|
166
199
|
|
|
167
|
-
## No-Code UI for checks and
|
|
200
|
+
## No-Code UI for checks, tracks and facts management
|
|
168
201
|
|
|
169
|
-
No-Code UI is a powerful user interface built into the Soundcheck plugin that allows users to manage checks and
|
|
202
|
+
No-Code UI is a powerful user interface built into the Soundcheck plugin that allows users to manage checks, tracks and facts without writing YAML code. Prior to No-Code UI, users had to write YAML code to configure a new check, track or fact. Now, non-programmers can add checks, tracks and facts too – thereby making it easier for everyone to work within Soundcheck.
|
|
170
203
|
|
|
171
|
-
No-Code UI has the same capabilities as its YAML configuration analog, however this capability simplifies and visualizes the process of managing checks and
|
|
204
|
+
No-Code UI has the same capabilities as its YAML configuration analog, however this capability simplifies and visualizes the process of managing checks, tracks and facts. Checks, tracks and facts created via No-Code UI are stored in the central Backstage database, or a [plugin-specific database](https://backstage.io/docs/tutorials/configuring-plugin-databases?__hstc=71158991.ce8f00825b31a2e008e99e7bf8c61d36.1687962480385.1687962480385.1687962480385.1&__hssc=71158991.1.1687962480385&__hsfp=2924083047#connection-configuration-per-plugin) if configured.
|
|
172
205
|
|
|
173
|
-
The No-Code UI will allow non-programmers to easily manage checks and
|
|
206
|
+
The No-Code UI will allow non-programmers to easily manage checks, tracks and facts via the Soundcheck UI without needing to write code. However, if a user wishes to, they can still continue to create checks, tracks and facts through Soundcheck’s YAML configuration.
|
|
174
207
|
|
|
175
208
|
## Using the No-Code UI
|
|
176
209
|
|
|
@@ -222,6 +255,42 @@ Once a track is created, you will be able to manage and edit your track on its d
|
|
|
222
255
|
|
|
223
256
|
As with checks, you can make as many changes as desired when editing tracks. Just make sure to save your track in order for changes to take effect. Also, similar to checks,, editing a track and saving will immediately reflect onto anything that has been assigned to said track.
|
|
224
257
|
|
|
258
|
+
### Fact Collectors
|
|
259
|
+
|
|
260
|
+
While Soundcheck comes with two built-in fact collectors: catalog and soundcheck, soundcheck can be extended with additional fact collectors. A fact collector can collect one or more facts on a given entity. At the moment, only Github fact collectors are supported for No Code UI, with support for others coming in future releases.
|
|
261
|
+
|
|
262
|
+

|
|
263
|
+
|
|
264
|
+
#### Configuring a fact collector
|
|
265
|
+
|
|
266
|
+
To configure a fact collector, make sure you are on the Collectors tab. Click on a Fact's “Configure” link to open a modal that displays the Fact Collector's configuration form.
|
|
267
|
+
|
|
268
|
+
- WARNING: If you already have a config YAML file setup, you will be unable to use No-Code UI to configure your collector. In order to use the No-Code UI, simply remove the YAML file/reference and you will have access to configure from No-Code UI.
|
|
269
|
+
|
|
270
|
+

|
|
271
|
+
|
|
272
|
+
Once you choose to configure a collector, you will see the following page with 3 configuration options. You can see what each configuration collects in its description. All 3 configs have the following options:
|
|
273
|
+
|
|
274
|
+
#### Frequency
|
|
275
|
+
|
|
276
|
+

|
|
277
|
+
|
|
278
|
+
You can set the frequency of how often to collect details from each collector option. The frequency of runs can be set using regular intervals or defined as custom cron expressions.
|
|
279
|
+
|
|
280
|
+
#### Filters
|
|
281
|
+
|
|
282
|
+

|
|
283
|
+
|
|
284
|
+
You can set filters for each option as well. These filters contain the same options as Tracks. You can learn by going to the [Creating a new track](#creating-a-new-track) section.
|
|
285
|
+
|
|
286
|
+
#### Caching
|
|
287
|
+
|
|
288
|
+

|
|
289
|
+
|
|
290
|
+
Lastly, you can enable Caching and set up an optional duration for said cache.
|
|
291
|
+
|
|
292
|
+
Once you have finished making your desired changes, make sure to click on the save button in order to properly save you configuration. Optionally, you can click on the cancel button at anytime to discard your changes..
|
|
293
|
+
|
|
225
294
|
## RBAC Integration
|
|
226
295
|
|
|
227
296
|
Along with the No Code UI release, we have recently integrated Soundcheck with the [RBAC plugin](https://backstage.spotify.com/plugins/rbac/). Admins can now use the RBAC plugin to manage (allow and restrict) what individual users or groups can do within Soundcheck.
|
|
@@ -231,3 +300,59 @@ Soundcheck’s No-Code UI integrates with Backstage’s permission framework on
|
|
|
231
300
|

|
|
232
301
|
|
|
233
302
|
Take a look at the [RBAC Integration](https://backstage.spotify.com/plugins/rbac/) for details and [RBAC Readme](https://www.npmjs.com/package/@spotify/backstage-plugin-rbac) for steps.
|
|
303
|
+
|
|
304
|
+
## Soundcheck Tech Health Page
|
|
305
|
+
|
|
306
|
+
Soundcheck has the capability to aggregate, filter, and display check result and certification data.
|
|
307
|
+
The `pass rate` is the aggregation metric representing the percentage of check results or
|
|
308
|
+
certifications marked as 'passed' within a filterable group of current check results or certifications
|
|
309
|
+
for the date the metric is calculated.
|
|
310
|
+
|
|
311
|
+
The tech health page is available at the following link:
|
|
312
|
+
http://[hostname]:[port]/soundcheck/tech-health
|
|
313
|
+
|
|
314
|
+

|
|
315
|
+
|
|
316
|
+
### Aggregations
|
|
317
|
+
|
|
318
|
+
The check result and certification data can be aggregated by:
|
|
319
|
+
|
|
320
|
+
- `Checks`: Pass rates for checks, either organization-wide or filtered by specific checks,
|
|
321
|
+
tracks/levels, and entities based on the selections.
|
|
322
|
+
- `Tracks`: Pass rates for track levels, either organization-wide or filtered by specific checks,
|
|
323
|
+
tracks/levels, and entities based on the selections.
|
|
324
|
+
- `Entities`: Pass rates for entities, either organization-wide or filtered by specific checks,
|
|
325
|
+
tracks/levels, and entities based on the selections.
|
|
326
|
+
- `Teams`: Pass rates for teams, either organization-wide or filtered by specific checks,
|
|
327
|
+
tracks/levels, and entities based on the selections.
|
|
328
|
+
|
|
329
|
+
### Filters
|
|
330
|
+
|
|
331
|
+
The data can be filtered by the following categories:
|
|
332
|
+
|
|
333
|
+
- `Entities`: check and certification pass rates will be calculated only for selected entities.
|
|
334
|
+
- `Entity Owners`: check and certification pass rates will be calculated only for the entities
|
|
335
|
+
owned by selected teams and their child teams recursively.
|
|
336
|
+
- `Tracks`: check and certification pass rates will be calculated only for selected tracks and
|
|
337
|
+
checks included in these tracks.
|
|
338
|
+
- `Track Levels`: check and certification pass rates will be calculated only for selected track
|
|
339
|
+
levels and checks included in these track levels.
|
|
340
|
+
- `Checks`: check pass rates will be calculated only for selected checks. Certification pass rates
|
|
341
|
+
will be calculated only for track levels that include these checks.
|
|
342
|
+
- `Check Owners`: check pass rates will be calculated only for the checks owned by selected teams.
|
|
343
|
+
Certification pass rates will be calculated only for track levels that include checks owned by
|
|
344
|
+
selected teams.
|
|
345
|
+
|
|
346
|
+
Filter rules:
|
|
347
|
+
|
|
348
|
+
- If no filter values are selected the pass rates will be calculated across the entire organization.
|
|
349
|
+
- Filter values within the same category are treated as ANY (OR).
|
|
350
|
+
- Filter values within different categories are treated as ALL (AND).
|
|
351
|
+
|
|
352
|
+
### Trends
|
|
353
|
+
|
|
354
|
+
The pass rate metric can be calculated for up to the last 90 days so that the pass rates can be monitored over time.
|
|
355
|
+
Check result history and certification history must be enabled in order to be able to see the trend data:
|
|
356
|
+
|
|
357
|
+
- [Enabling check result history](https://www.npmjs.com/package/@spotify/backstage-plugin-soundcheck-backend#enabling-check-result-history)
|
|
358
|
+
- [Enabling certification history](https://www.npmjs.com/package/@spotify/backstage-plugin-soundcheck-backend#enabling-certification-history)
|
package/dist/esm/{EntitySoundcheckContent-52a2a214.esm.js → EntitySoundcheckContent-592fa779.esm.js}
RENAMED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import e,{useState as W,useEffect as $}from"react";import{Link as O,useParams as Q,Routes as j,Route as k,Navigate as I}from"react-router-dom";import{makeStyles as p,Typography as f,Box as U,Tab as L,Tabs as T,Paper as V,Divider as Y}from"@material-ui/core";import{SpotifyLicenseBanner as q}from"@spotify/backstage-plugin-core";import{useEntity as u}from"@backstage/plugin-catalog-react";import{R as G}from"./RefetchingIndicator-
|
|
2
|
-
//# sourceMappingURL=EntitySoundcheckContent-
|
|
1
|
+
import e,{useState as W,useEffect as $}from"react";import{Link as O,useParams as Q,Routes as j,Route as k,Navigate as I}from"react-router-dom";import{makeStyles as p,Typography as f,Box as U,Tab as L,Tabs as T,Paper as V,Divider as Y}from"@material-ui/core";import{SpotifyLicenseBanner as q}from"@spotify/backstage-plugin-core";import{useEntity as u}from"@backstage/plugin-catalog-react";import{R as G}from"./RefetchingIndicator-b042ec49.esm.js";import{s as H,R as o,A as y,F as B,a as J,u as x,L as K,N as X,b as C,c as g,d as Z,C as _,e as ee,i as te,f as F,S as ae}from"./index-95ae147b.esm.js";import{Skeleton as s}from"@material-ui/lab";import{MarkdownContent as P}from"@backstage/core-components";import{stringifyEntityRef as ne}from"@backstage/catalog-model";import{useApi as re,useRouteRef as b,useRouteRefParams as ie}from"@backstage/core-plugin-api";import{useQuery as le}from"@tanstack/react-query";import ce from"react-use/lib/useMeasure";import A from"react-use/lib/usePrevious";import oe from"react-confetti";import"react-use/lib/useDebounce";import"graphql-request";import"graphql-tag";import"lodash";import"@material-ui/core/styles/makeStyles";import"classnames";import"@material-ui/icons/Schedule";import"luxon";import"@material-ui/icons/Check";import"@material-ui/icons/Close";import"@material-ui/icons/RemoveCircleOutline";import"@material-ui/icons/HelpOutline";function se(t,n,a){const r=re(H),i=ne(t);return le(["soundcheck/check-details",i,n,a],async()=>r.getCheckResultDetails(i,n,a),{enabled:!!n&&!!a})}const me=p({markdownContent:{"& :last-child":{marginBottom:0}}}),de=({state:t,notes:n})=>{const a=me(),r={[o.Passed]:"success",[o.Failed]:"error",[o.NotReported]:"info",[o.NotApplicable]:"info"}[t],i={[o.Passed]:"Check passed",[o.Failed]:"Check did not pass",[o.NotReported]:"Check not reported",[o.NotApplicable]:"Check not applicable"}[t];return e.createElement(y,{severity:r,title:i},n?e.createElement(P,{className:a.markdownContent,content:n}):null)},pe=()=>{const t=D();return e.createElement(B,null,e.createElement("div",{className:t.root,"data-testid":"check-details-view"},e.createElement("div",{className:t.topBar},e.createElement(f,{variant:"h2",className:t.title},e.createElement(s,{width:300,height:32})),e.createElement(s,{width:100,height:32})),e.createElement(s,{variant:"rect",height:120}),e.createElement("div",{"data-testid":"soundcheck-check-details-description"},e.createElement(f,{variant:"h3"},e.createElement(s,null)),e.createElement(s,null),e.createElement(s,null),e.createElement(s,null))))},D=p(t=>({root:{padding:`${t.spacing(3)}px ${t.spacing(5)}px`},title:{fontWeight:"normal",fontSize:t.typography.h5.fontSize},description:{padding:`${t.spacing(3)}px 0`},subtitle:{fontWeight:"normal",fontSize:t.typography.h6.fontSize},topBar:{display:"flex",justifyContent:"space-between",marginBottom:t.spacing(2)}})),ue=({programId:t,checkId:n})=>{const a=D(),{entity:r}=u(),{data:i,isLoading:l,isError:c}=se(r,t,n);if(c)return e.createElement(U,{padding:2},e.createElement(y,{severity:"error",title:"Error loading check details"}));if(l||!t||!n)return e.createElement(pe,null);if(!i)return null;const{name:h,description:d,result:v,timestamp:m,notes:E}=i;return e.createElement("div",{className:a.root,"data-testid":"check-details-view"},e.createElement("div",{className:a.topBar},e.createElement(f,{variant:"h2",className:a.title},h),m?e.createElement(J,{timestamp:m,description:"Last updated"}):null),e.createElement(de,{state:v,notes:E}),e.createElement("div",{className:a.description,"data-testid":"soundcheck-check-details-description"},e.createElement(f,{variant:"h3",className:a.subtitle},"Description"),e.createElement(P,{content:d})))},he=p(()=>({root:{position:"absolute",width:"100%",height:"100%"}})),Ee=({programId:t})=>{var n,a;const r=he(),{entity:i}=u(),{data:l,isLoading:c}=x(i,t),[h,{width:d,height:v}]=ce(),m=c?void 0:(a=(n=l==null?void 0:l.highestLevel)==null?void 0:n.ordinal)!=null?a:-1,E=A(m),R=A(t),[M,S]=W(!1);return $(()=>{typeof E!="undefined"&&typeof m!="undefined"&&t===R&&m>E&&S(!0)},[m,E,t,R]),M?e.createElement("div",{ref:h,className:r.root},e.createElement(oe,{width:d,height:v,numberOfPieces:1e3,gravity:1,initialVelocityY:20,recycle:!1,onConfettiComplete:()=>S(!1)})):null},z=p(t=>({root:{maxWidth:"80ch",textTransform:"uppercase",paddingTop:t.spacing(2),paddingBottom:t.spacing(2)},wrapper:{display:"inline-block",textOverflow:"ellipsis",whiteSpace:"nowrap",overflow:"hidden"},badge:{marginRight:t.spacing(1)}})),fe=({id:t,name:n,badge:a,href:r,selected:i=!1})=>{const l=z();return e.createElement(L,{className:l.root,classes:{wrapper:l.wrapper},value:t,label:e.createElement(e.Fragment,null,a?e.createElement(K,{badge:a,className:l.badge}):e.createElement(X,{className:l.badge}),n),component:O,to:r,selected:i})},w=()=>{const t=z();return e.createElement(L,{className:t.root,classes:{wrapper:t.wrapper},label:e.createElement(s,{width:180})})},ge=()=>e.createElement(B,null,e.createElement(T,{value:!1,indicatorColor:"primary"},e.createElement(w,null),e.createElement(w,null),e.createElement(w,null)));function ve(t=[],n){const a=t.findIndex(r=>r.program.id===n);return a<0?!1:a}const ke=({trackId:t})=>{const{entity:n}=u(),{isLoading:a,data:r}=C(n),i=b(g);if(a||!t)return e.createElement(ge,null);const l=ve(r,t);return e.createElement(T,{value:l,indicatorColor:"primary","aria-label":"Certifications",variant:"scrollable"},r&&r.map(({program:{id:c,name:h},highestLevel:d})=>e.createElement(fe,{key:c,id:c,name:h,badge:d==null?void 0:d.badge,selected:c===t,href:i({trackId:c})})))},ye=p({paper:{overflow:"hidden",position:"relative"},view:{display:"grid",gridTemplateColumns:"1fr 2fr"}}),Ce=()=>{const{trackId:t,checkId:n}=Q(),a=ye(),{entity:r}=u(),{isError:i,isFetched:l,data:c}=C(r);return i?e.createElement(y,{severity:"error",title:"Error loading certifications"}):l&&!(c!=null&&c.length)?e.createElement(Z,null):e.createElement(V,{className:a.paper},e.createElement(G,null),e.createElement(ke,{trackId:t}),e.createElement(Y,null),e.createElement("div",{"data-testid":"soundcheck-certification-view",className:a.view},e.createElement(_,{trackId:t,checkId:n}),e.createElement(ue,{programId:t,checkId:n}),e.createElement(Ee,{programId:t})))},be=p(t=>({root:{"&:not(:first-child)":{marginTop:t.spacing(2)}}})),N=()=>{const t=be();return e.createElement(e.Fragment,null,e.createElement(q,{backend:ee,invalidLicenseMessage:te,inline:!0}),e.createElement("div",{className:t.root},e.createElement(Ce,null)))},we=()=>{var t;const{entity:n}=u(),a=b(g),{data:r}=C(n),i=(t=r==null?void 0:r[0])==null?void 0:t.program.id;return i?e.createElement(I,{to:a({trackId:i}),replace:!0}):null},Ne=()=>{var t,n;const{entity:a}=u(),{trackId:r}=ie(g),i=b(F),{data:l}=x(a,r),c=(n=(t=l==null?void 0:l.levels[0])==null?void 0:t.checks[0])==null?void 0:n.id;return c?e.createElement(I,{to:i({trackId:r,checkId:c}),replace:!0}):null},Re=()=>e.createElement(j,null,e.createElement(k,{path:"/",element:e.createElement(e.Fragment,null,e.createElement(N,null),e.createElement(we,null))}),e.createElement(k,{path:g.path,element:e.createElement(e.Fragment,null,e.createElement(N,null),e.createElement(Ne,null))}),e.createElement(k,{path:F.path,element:e.createElement(N,null)})),Se=()=>e.createElement(ae,null,e.createElement(Re,null));export{Se as EntitySoundcheckContent};
|
|
2
|
+
//# sourceMappingURL=EntitySoundcheckContent-592fa779.esm.js.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import t,{useState as I,useEffect as v,useMemo as O,useCallback as j,createContext as me,useContext as ue,memo as b,Fragment as ge}from"react";import{useSearchParams as he}from"react-router-dom";import{makeStyles as f,alpha as M,TextField as fe,CircularProgress as ye,Tooltip as K,LinearProgress as ve,withStyles as ke,Grid as C,Typography as k}from"@material-ui/core";import Ee from"@material-ui/lab/Autocomplete";import{stringifyEntityRef as W,parseEntityRef as w}from"@backstage/catalog-model";import{useApi as E,identityApiRef as U,useRouteRef as P,configApiRef as be}from"@backstage/core-plugin-api";import{useQuery as A}from"@tanstack/react-query";import{s as D,R as N,h as Ce,B as we,L as _,N as Q,A as Ne,d as Re,j as $e}from"./index-95ae147b.esm.js";import{catalogApiRef as G,humanizeEntityRef as T,entityRouteRef as F}from"@backstage/plugin-catalog-react";import xe from"react-use/lib/useAsync";import{HeaderTabs as q,MarkdownContent as Te,Link as B,EmptyState as Le}from"@backstage/core-components";import{R as Ie}from"./RefetchingIndicator-b042ec49.esm.js";import{countBy as J}from"lodash";import{Skeleton as S}from"@material-ui/lab";import{VariableSizeGrid as Oe}from"react-window";function X(e,r){const a=E(D);return A(["soundcheck/track-overview-for-owner",e,r],async()=>a.getProgramOverviewForOwner(e,r),{enabled:!!e&&!!(r!=null&&r.kind)})}function Y(){const e=E(G);return A(["soundcheck/all-groups"],async()=>{const{items:r}=await e.getEntities({filter:{kind:"Group"},fields:["spec.profile.displayName","metadata.title","metadata.name","metadata.namespace","kind"]});return r.filter(a=>(a==null?void 0:a.kind)==="Group").map(a=>{var n,l,i,s;return{name:(s=(i=(l=(n=a.spec)==null?void 0:n.profile)==null?void 0:l.displayName)!=null?i:a.metadata.title)!=null?s:a.metadata.name,ref:W(a)}})},{staleTime:5*60*1e3,refetchInterval:!1,refetchOnWindowFocus:!1})}function Pe(){const e=E(U),r=E(G);return A(["soundcheck/user-groups-claims"],async()=>{const{ownershipEntityRefs:a}=await e.getBackstageIdentity();return(await r.getEntitiesByRefs({entityRefs:a})).items.filter(n=>(n==null?void 0:n.kind)==="Group").map(n=>{var l,i,s,c;return{name:(c=(s=(i=(l=n.spec)==null?void 0:l.profile)==null?void 0:i.displayName)!=null?s:n.metadata.title)!=null?c:n.metadata.name,ref:W(n)}})})}function Ae(e){const r=E(D);return A(["soundcheck/facets-for-owner",e],async()=>r.getFacetsForOwner(e),{enabled:!!e})}const Fe=()=>{const[e,r]=he(),a=Object.fromEntries(e.entries()),[n,l]=I(a);return v(()=>{r(n,{replace:!0})},[n]),[n,l]},Z=()=>{const{data:e,isLoading:r,isError:a}=Pe(),{data:n,isLoading:l,isError:i}=Y();return{options:O(()=>{const s=[];return e&&s.push(...e.map(({name:c,ref:o})=>({name:c,ref:o,key:"My Groups"}))),n&&s.push(...n.map(({name:c,ref:o})=>({name:c,ref:o,key:"All Groups"}))),s},[e,n]),isLoading:r||l,isError:a||i}},Be=f(e=>({root:{width:"100%",minWidth:250},textField:{"& $notchedOutline":{borderColor:M(e.page.fontColor,.25)},"&:hover $notchedOutline":{borderColor:e.page.fontColor}},input:{backgroundColor:"transparent",color:e.page.fontColor},clearIndicator:{color:e.page.fontColor},popupIndicator:{color:e.page.fontColor},notchedOutline:{}})),Se=e=>{const{onChange:r,initialValue:a,setError:n}=e,{options:l,isLoading:i,isError:s}=Z(),c=Be(),[o,d]=I(null);v(()=>{if(!i&&l!=null&&l.length&&!o){const m=a?l.find(p=>p.ref===a):l[0];m&&(d(m),r==null||r(m.ref))}},[i,l,o,r,a]);const u=j((m,p)=>{d(p),r==null||r(p==null?void 0:p.ref)},[r,d]);return v(()=>{n==null||n(s?new Error("Error loading groups"):void 0)},[s,n]),s?null:t.createElement(Ee,{"aria-label":"Current group",className:c.root,classes:{clearIndicator:c.clearIndicator,popupIndicator:c.popupIndicator},disableClearable:!0,options:l!=null?l:[],loading:i,groupBy:m=>m.key,value:o,freeSolo:!1,onChange:u,getOptionLabel:m=>m.name,renderInput:m=>t.createElement(fe,{...m,variant:"outlined",placeholder:i?"Loading":"Select a group",className:c.textField,InputProps:{...m.InputProps,className:c.input,classes:{notchedOutline:c.notchedOutline},endAdornment:t.createElement(t.Fragment,null,i?t.createElement(ye,{color:"inherit",size:20}):null,m.InputProps.endAdornment)}})})},ee={loading:!1},te=me(ee),ze=()=>ue(te),He=({children:e})=>{const[r,a]=I(ee),n=E(G),l=E(U),{value:i,loading:s,error:c}=xe(async()=>{const[{token:o},d]=await Promise.all([l.getCredentials(),l.getBackstageIdentity()]);return o?await n.getEntityByRef(d.userEntityRef):null},[n,l]);return v(()=>{if(i){const o=W(i);a({user:i,userEntityRef:o,loading:s,error:c})}else a({loading:s,error:c})},[i,s,c]),t.createElement(te.Provider,{value:r},e)},We=e=>({key:`skeleton${e}`,label:"",id:`skeleton${e}`}),Ge=()=>{const e=Array.from({length:4},(r,a)=>We(a));return t.createElement(q,{tabs:e})},Ve=f(e=>({root:{borderTop:`1px solid ${e.palette.divider}`,borderBottom:`1px solid ${e.palette.divider}`},tab:{textTransform:"uppercase",paddingTop:e.spacing(2),paddingBottom:e.spacing(2)}})),je=({unfilteredFacets:e,onChange:r,kind:a,type:n})=>{var l,i,s;const c=Ve(),o={types:(l=e==null?void 0:e.types.filter(({count:p})=>p>0))!=null?l:[]},d=j(p=>{var g;r((g=o==null?void 0:o.types[p].kind)!=null?g:"",o==null?void 0:o.types[p].type)},[o==null?void 0:o.types,r]);v(()=>{var p,g,y;const h=(o==null?void 0:o.types)&&o.types.length>=0,L=!a&&h,H=a&&h&&!(o!=null&&o.types.find(({kind:$,type:x})=>a===$&&(!n&&!x||n===x)));(L||H)&&r((g=(p=o==null?void 0:o.types[0])==null?void 0:p.kind)!=null?g:"",(y=o==null?void 0:o.types[0])==null?void 0:y.type)},[a,n,o==null?void 0:o.types,r]);const u=(i=o==null?void 0:o.types.map(({kind:p,type:g,count:y})=>{const h=`${p}|${g!=null?g:""}`;return{key:h,label:`${g!=null?g:p} (${y>50?"50+":y})`,id:h,tabProps:{className:c.tab}}}))!=null?i:[];if(!u.length)return null;const m=(s=o==null?void 0:o.types.findIndex(p=>p.kind===a&&(!p.type&&!n||p.type===n)))!=null?s:-1;return t.createElement(t.Fragment,null,t.createElement(Ie,null),t.createElement(q,{onChange:d,tabs:u,selectedIndex:m>-1?m:void 0}))},Me=f(e=>({root:{height:"8px",minWidth:"64px",marginLeft:e.spacing(2),borderRadius:"100vh",backgroundColor:e.palette.background.default},bar:{backgroundColor:e.palette.success.main,transition:"none"}})),re=e=>{var r,a;const n=Me(e),l=O(()=>Object.entries(e.progress).reduce((s,[,c])=>s+c,0),[e.progress]);if(l===0)return null;const i=(r=e.progress[N.Passed])!=null?r:0;return t.createElement(K,{arrow:!0,title:`Check passing for ${i} of ${l} ${l===1?"entity":"entities"}`,enterDelay:0,placement:"top"},t.createElement(ve,{variant:"determinate",value:((a=e.progress[N.Passed])!=null?a:0)/l*100,classes:{root:n.root,bar:n.bar}}))},Ke=f(e=>({headerWrapper:{marginTop:e.spacing(.5)},entityRefName:{fontWeight:"bold"},iconWrapper:{padding:e.spacing(1.5,.5),display:"flex",alignItems:"center",justifyContent:"center"}})),Ue=({check:{name:e,description:r},icon:a,entityRef:n})=>{const l=Ke(),i=w(n);return t.createElement(C,{spacing:1},t.createElement(C,{container:!0,direction:"row",spacing:1,wrap:"nowrap"},t.createElement("div",{className:l.iconWrapper},a),t.createElement(k,{variant:"h6",className:l.headerWrapper,noWrap:!0},e)),t.createElement(C,{item:!0,wrap:"nowrap"},t.createElement(k,{variant:"subtitle2",className:l.entityRefName},T(i,{defaultKind:i.kind}))),t.createElement(Te,{content:r}))},De=ke(e=>{const r=e.palette.type==="dark"?e.palette.common.black:e.palette.grey[300];return{tooltip:{backgroundColor:r,color:e.palette.type==="dark"?e.palette.common.white:e.palette.grey[700]},arrow:{color:r}}})(K),_e=({children:e,check:r,icon:a,entityRef:n})=>t.createElement(De,{arrow:!0,title:t.createElement(Ue,{check:r,icon:a,entityRef:n}),enterDelay:150,placement:"top"},e),Qe=f(e=>({root:{padding:0},iconWrapper:{padding:e.spacing(1.5),display:"flex",alignItems:"center",justifyContent:"center"},link:{"&:hover $iconWrapper, &:active $iconWrapper, &:focus $iconWrapper":{backgroundColor:e.palette.infoBackground}},icon:{width:"17px",height:"17px"},virtualized:{borderBottom:`1px solid ${e.palette.divider}`,borderRight:`1px solid ${e.palette.divider}`}})),ae=b(({programId:e,check:r,entityRef:a,result:n,entityRoute:l,isVirtualized:i})=>{const s=Qe();if(typeof a!="string"){const u=t.createElement("div",{className:s.iconWrapper},t.createElement("div",{className:s.icon}));return i?t.createElement("div",{className:`${s.root} ${s.virtualized}`,"aria-hidden":!0},u):t.createElement("td",{className:s.root,"aria-hidden":!0},u)}const c=t.createElement(Ce,{className:s.icon,result:n!=null?n:N.NotReported}),o=t.createElement("div",{className:s.iconWrapper},c),d=n&&n===N.NotApplicable?o:t.createElement(B,{className:s.link,to:`${l(w(a))}/soundcheck/${e}/${r.id}`},o);return i?t.createElement("div",{className:`${s.root} ${s.virtualized}`},t.createElement(_e,{check:r,icon:c,entityRef:a},d)):t.createElement("td",{className:`${s.root}`},d)}),ne=8,qe=16,R={programTitle:70,levelTitle:30,check:42,entityRefFooter:100},z={programTitle:350+qe*2,checkResult:42},Je=e=>e.reduce((r,a)=>r+a.height,0),Xe=e=>e*z.checkResult+z.programTitle,Ye=e=>e.filter(r=>r!==void 0).map(r=>{const a=w(r);return T(a,{defaultKind:a.kind})}).reduce((r,a)=>r.length>a.length?r:a,""),Ze=e=>ne*e+ne,le="NoLevel",et=e=>({name:le,badge:{options:{level:0,color:""},variant:we.Medal},entityRef:e,ordinal:0}),oe=f(e=>({checkNameCell:{padding:0,backgroundColor:e.palette.background.paper},checkNameContent:{padding:`0 ${e.spacing(2)}px`,display:"flex",justifyContent:"space-between",alignItems:"center"},checkNameTypography:{overflow:"hidden",textOverflow:"ellipsis"},checkIndicator:{flexBasis:e.spacing(8)},checkNameCellVirtualized:{height:`${R.check}px`,lineHeight:`${R.check}px`,borderBottom:`1px solid ${e.palette.divider}`,borderRight:`1px solid ${e.palette.divider}`}})),tt=b(({programId:e,programName:r,check:a,entityRefs:n,results:l,entityRoute:i})=>{const s=oe(),c=O(()=>J(l.filter(({result:d})=>d!==N.NotApplicable),"result"),[l]),o=new Map(l.map(d=>[d.entityRef,d.result]));return t.createElement("tr",{"data-testid":"track-check-row"},t.createElement("th",{scope:"row",className:s.checkNameCell,"aria-label":`${a.name} check for ${r} track`},t.createElement("div",{className:s.checkNameContent},t.createElement(k,{className:s.checkNameTypography,variant:"subtitle2",component:"p"},a.name),t.createElement(re,{className:s.checkIndicator,progress:c}))),n.map((d,u)=>t.createElement(ae,{key:u,programId:e,check:a,entityRef:d,result:typeof d=="string"?o.get(d):void 0,entityRoute:i})))}),rt=({name:e,progress:r})=>{const a=oe();return t.createElement("div",{className:a.checkNameCell,"aria-label":`${e} check`},t.createElement("div",{className:`${a.checkNameContent} ${a.checkNameCellVirtualized}`},t.createElement(k,{variant:"subtitle2",component:"p",className:a.checkNameTypography},e),t.createElement(re,{className:a.checkIndicator,progress:r})))},at=f(e=>({virtualized:{borderRight:`1px solid ${e.palette.divider}`,height:`${R.programTitle}px`,display:"flex",justifyContent:"center",alignItems:"center"}})),nt=b(({entityRef:e,highestLevels:r})=>{const a=r.find(n=>n.entityRef===e);return t.createElement(t.Fragment,null,a!=null&&a.badge?t.createElement(_,{badge:a.badge}):t.createElement(Q,null))}),lt=({highestLevel:e})=>{const r=at();if(!(e!=null&&e.badge))return t.createElement("div",{className:r.virtualized},"\xA0");const a=e.name!==le;return t.createElement("div",{className:r.virtualized},a?t.createElement(_,{badge:e.badge}):t.createElement(Q,null))},ie=f(e=>({programNameCell:{padding:0,position:"sticky",backgroundColor:e.palette.background.paper},programNameContent:{padding:e.spacing(2)},programNameTypography:{overflow:"hidden",textOverflow:"ellipsis"},badgeCellContent:{display:"flex",justifyContent:"center",alignItems:"center"},programNameCellVirtualized:{borderRight:`1px solid ${e.palette.divider}`}})),ot=b(({program:e,entityRefs:r,highestLevels:a})=>{const n=ie();return t.createElement("tr",{"data-testid":"track-title-row"},t.createElement("th",{scope:"row",className:n.programNameCell},t.createElement("div",{className:n.programNameContent},t.createElement(k,{className:n.programNameTypography,variant:"h5",component:"p"},e.name))),r.map((l,i)=>typeof l!="string"?t.createElement("td",{key:i,"aria-hidden":!0}):t.createElement("td",{key:i,"data-testid":"track-certification-cell"},t.createElement("div",{className:n.badgeCellContent},t.createElement(nt,{entityRef:l,highestLevels:a})))))}),it=b(({name:e})=>{const r=ie();return t.createElement("div",{className:`${r.programNameCell} ${r.programNameCellVirtualized}`},t.createElement("div",{className:r.programNameContent},t.createElement(k,{className:r.programNameTypography,variant:"h5",component:"p"},e)))}),V=f(e=>{const r=e.palette.type==="dark"?e.palette.grey[700]:e.palette.grey[100];return{root:{color:M(e.palette.getContrastText(r),.8),backgroundColor:r},levelContent:{padding:`${e.spacing(.5)}px ${e.spacing(2)}px`,backgroundColor:r},levelTypography:{overflow:"hidden",textOverflow:"ellipsis"},levelHeaderCell:{padding:`${e.spacing(.5)}px ${e.spacing(2)}px`,borderRight:`1px solid ${e.palette.divider}`,height:`${R.levelTitle}px`}}}),st=b(({level:e,entityRefs:r,programName:a})=>{const n=V();return t.createElement("tr",{className:n.root,"data-testid":"track-level-row"},t.createElement("th",{scope:"row",className:n.root},t.createElement("div",{className:n.levelContent},t.createElement(k,{className:n.levelTypography,variant:"subtitle2",component:"p","aria-label":`${e.name} for ${a} track`},e.name))),r.map((l,i)=>t.createElement("td",{key:i,className:n.root,"aria-hidden":!0})))}),ct=({name:e})=>{const r=V();return t.createElement("div",{className:`${r.levelHeaderCell} ${r.root}`,"aria-label":`${e}`},t.createElement(k,{variant:"subtitle2",component:"p",className:r.levelTypography},e))},dt=()=>{const e=V();return t.createElement("div",{className:`${e.levelHeaderCell} ${e.root}`},"\xA0")},pt=({program:e,highestLevels:r,levels:a,entityRefs:n,entityRoute:l})=>t.createElement("tbody",null,t.createElement(ot,{program:e,entityRefs:n,highestLevels:r}),a.map((i,s)=>t.createElement(ge,{key:s},t.createElement(st,{entityRefs:n,level:i,programName:e.name}),i.checks.map(({check:c,results:o},d)=>t.createElement(tt,{key:d,check:c,programId:e.id,programName:e.name,entityRefs:n,results:o,entityRoute:l}))))),se=f(e=>({root:{position:"sticky",bottom:"-1px",backgroundColor:e.palette.background.default,boxShadow:`0 -1px ${e.palette.divider}`,"& td$cell, & th$cell":{border:0,padding:e.spacing(1)},"& td$cell":{backgroundColor:e.palette.background.default}},row:{boxShadow:`1px 0 ${e.palette.background.default}, -1px 0 ${e.palette.background.default}`},cell:{verticalAlign:"top"},cellInner:{textOrientation:"mixed",writingMode:"vertical-lr",transform:"rotate(-20deg)",transformOrigin:`100% ${e.spacing(1)}px`,wordBreak:"keep-all",fontWeight:"bold",overflow:"hidden",textOverflow:"ellipsis",maxHeight:"max(15vh, 175px)"}})),mt=({entityRefs:e})=>{const r=P(F),a=se();return t.createElement("tfoot",{className:a.root,"data-testid":"results-table-footer"},t.createElement("tr",{className:a.row},t.createElement("td",{className:a.cell}),e.map((n,l)=>{if(typeof n!="string")return t.createElement("th",{key:l,className:a.cell,"aria-hidden":!0});const i=w(n);return t.createElement("th",{scope:"col",key:l,className:a.cell},t.createElement("div",{className:a.cellInner},t.createElement(B,{to:r(i)},T(i,{defaultKind:i.kind}))))})))},ut=({entityRef:e})=>{const r=P(F),a=se(),n=e?w(e):void 0,l=n?t.createElement(B,{to:r(n)},T(n,{defaultKind:n.kind})):t.createElement(t.Fragment,null);return t.createElement("div",{className:a.cell},t.createElement("div",{className:a.cellInner},l))},gt=f(e=>({table:{backgroundColor:e.palette.background.paper,borderCollapse:"collapse",whiteSpace:"nowrap","& th, & td":{border:`1px solid ${e.palette.divider}`,borderCollapse:"collapse"},paddingBottom:e.spacing(2)},programTitle:{padding:e.spacing(2)},checkResult:{padding:e.spacing(1.5)},title:{padding:`${e.spacing(1)}px ${e.spacing(2)}px`},header:{backgroundColor:e.palette.type==="dark"?e.palette.grey[700]:e.palette.grey[100]}})),ce=()=>{const e=gt(),r=new Array(25).fill(void 0),a=new Array(5).fill(void 0),n=new Array(3).fill(void 0);return t.createElement("table",{className:e.table},t.createElement("tbody",null,t.createElement("tr",null,t.createElement("td",{className:e.programTitle},t.createElement(S,{width:180,height:40})),r.map((l,i)=>t.createElement("td",{key:i}))),n.map((l,i)=>t.createElement(t.Fragment,{key:i},t.createElement("tr",{className:e.header},t.createElement("td",{className:e.title},t.createElement(S,{width:180})),r.map((s,c)=>t.createElement("td",{key:c}))),a.map((s,c)=>t.createElement("tr",{key:c},t.createElement("td",{className:e.title},t.createElement(S,{width:240})),r.map((o,d)=>t.createElement("td",{key:d,className:e.checkResult},t.createElement(S,{width:18,height:18,variant:"rect"})))))))))},ht=f(e=>({root:{width:"100%"},table:{overflow:"auto",backgroundColor:e.palette.background.paper,borderCollapse:"collapse",whiteSpace:"nowrap",textAlign:"left","& th, & td":{border:`1px solid ${e.palette.divider}`,borderCollapse:"collapse"},"& th:first-of-type":{position:"sticky",left:0,zIndex:1,maxWidth:"60ch"},"& tfoot":{bottom:0,zIndex:1e3},"& tbody td:first-of-type":{border:`1px solid ${e.palette.divider}`,boxShadow:`1px 0 ${e.palette.background.default}, -1px 0 ${e.palette.background.default}`}}})),ft=b(e=>{const{setError:r,kind:a,type:n,ownerEntityRef:l}=e,i=ht(),s=P(F),{data:c,isLoading:o,isError:d}=X(l,{kind:a,type:n});if(v(()=>{r==null||r(d?new Error("Error loading track overview"):void 0)},[d,r]),o)return t.createElement(ce,null);if(!c||!l)return null;const{programs:u,entityRefs:m}=c;if(!o&&!u.length)return t.createElement(Le,{missing:"data",title:"Missing tracks",description:t.createElement(t.Fragment,null,"Looks like the group"," ",T(w(l),{defaultKind:"Group"})," ","doesn't own any ",n!=null?n:a," components that have Soundcheck tracks set up.",t.createElement("br",null),t.createElement("br",null),"If you're an administrator, you can learn more about configuring and filtering tracks in the"," ",t.createElement(B,{to:"https://www.npmjs.com/package/@spotify/backstage-plugin-soundcheck-backend#entity-filter"},"docs"),".")});if(d)return null;const p=m.length>=25?m:[...m,...Array.from({length:25-m.length},()=>{})];return t.createElement("div",{className:i.root},t.createElement("table",{className:i.table,"aria-label":"Check results"},u.map(({program:g,levels:y,highestLevels:h},L)=>t.createElement(pt,{key:L,program:g,entityRefs:p,levels:y,highestLevels:h,entityRoute:s})),t.createElement(mt,{entityRefs:p})))}),yt=e=>t.createElement(it,{name:e}),vt=e=>({type:"ProgramHeader",render:()=>yt(e)}),kt=e=>e?t.createElement(ct,{name:e}):t.createElement(dt,null),de=e=>({type:"LevelHeader",render:()=>kt(e)}),Et=(e,r)=>t.createElement(rt,{name:e,progress:r}),bt=(e,r)=>({type:"CheckTitle",render:()=>Et(e,r)}),Ct=(e,r,a,n,l)=>t.createElement(ae,{check:r,entityRef:a,entityRoute:l,programId:e,result:n,isVirtualized:!0}),wt=(e,r,a,n,l)=>({type:"CheckResult",render:()=>Ct(e,r,a,n,l)}),Nt=e=>t.createElement(ut,{entityRef:e}),pe=e=>({type:"EntityHeader",render:()=>Nt(e)}),Rt=e=>t.createElement(lt,{highestLevel:e}),$t=e=>({type:"LevelBadge",render:()=>Rt(e)}),xt=e=>r=>{const a=e[r.rowIndex].cells[r.columnIndex];return a?t.createElement("div",{style:r.style},a.render()):t.createElement("div",{style:r.style})},Tt=(e,r,a)=>{var n;const l=[];for(const{program:s,levels:c,highestLevels:o}of e){l.push({height:R.programTitle,cells:[vt(s.name),...r.map(d=>{const u=d?o.find(m=>m.entityRef===d)||et(d):void 0;return $t(u)})]});for(const d of c){l.push({height:R.levelTitle,cells:[de(d.name),...r.map(u=>de(""))]});for(const{check:u,results:m}of d.checks)l.push({height:R.check,cells:[bt(u.name,J(m.filter(({result:p})=>p!==N.NotApplicable),"result")),...r.map(p=>{var g,y;return wt(s.id,u,p,(y=(g=m.find(h=>h.entityRef===p))==null?void 0:g.result)!=null?y:N.NotApplicable,a)})]})}}const i=Ye(r!=null?r:[]);return l.push({height:Ze((n=i.length)!=null?n:1),cells:[pe(""),...r.map(s=>pe(s||""))]}),l},Lt=f(e=>({table:{backgroundColor:e.palette.background.paper,borderCollapse:"collapse",whiteSpace:"nowrap",textAlign:"left",overflow:"auto"}})),It=e=>{const{setError:r,kind:a,type:n,ownerEntityRef:l}=e,i=Lt(),s=P(F),{data:c,isLoading:o,isError:d}=X(l,{kind:a,type:n});if(v(()=>{r==null||r(d?new Error("Error loading program overview"):void 0)},[d,r]),o)return t.createElement(ce,null);if(!c||!l)return null;const{programs:u,entityRefs:m}=c,p=m.length>=25?m:[...m,...Array.from({length:25-m.length},()=>{})],g=Tt(u,p,s),y=xt(g);return t.createElement(C,{"aria-label":`Check results for ${n!=null?n:a}`,key:`${a}|${n!=null?n:""}`,item:!0,xs:12},t.createElement(Oe,{className:i.table,columnCount:p.length+1,columnWidth:h=>h===0?z.programTitle:z.checkResult,rowCount:g.length,rowHeight:h=>g[h].height,height:Je(g),width:Xe(p.length)},y))},Ot=({facets:e,ownerEntityRef:r,kind:a,type:n,setError:l})=>{const i=O(()=>{const s=new Map;return e.types.forEach(({kind:c,type:o})=>{const d=`${c}|${o!=null?o:""}`;s.set(d,t.createElement(It,{key:d,ownerEntityRef:r,kind:c,type:o,setError:l}))}),s},[e,r,l]);return t.createElement("div",null,i.get(`${a}|${n!=null?n:""}`))},Pt=f(()=>({scrollContainer:{overflow:"auto"}})),At=({facets:e,ownerEntityRef:r,hasError:a,kind:n,type:l,setError:i,useVirtualizedResultsTable:s,isFixedGroup:c})=>{var o,d,u;const m=Pt();if(a)return t.createElement(Ne,{severity:"error",title:a.message});const p="Use the groups drop-down list at the top-right of the page to select another group.";return e&&((d=(o=e.types)==null?void 0:o.length)!=null?d:0)>0?(u=e.types)!=null&&u.find(g=>g.count>0)?t.createElement("div",{className:m.scrollContainer},s?t.createElement(Ot,{facets:e,kind:n,type:l,setError:i,ownerEntityRef:r,hasError:a}):t.createElement(ft,{ownerEntityRef:r,kind:n,type:l,setError:i})):t.createElement(Re,{description:t.createElement(t.Fragment,null,"Looks like the group '",T(w(r),{defaultKind:"Group"}),"' doesn't own any entities that have any applicable tracks configured.",!c&&t.createElement(t.Fragment,null,t.createElement("br",null),t.createElement("br",null),p))}):t.createElement($e,{ownerEntityRef:r,selectGroupHint:c?void 0:p})},Ft=f(()=>({tableContainer:{padding:0,backgroundColor:"transparent"}})),Bt=({groupSelectorError:e,searchParams:r,setSearchParams:a,isFixedGroup:n=!1})=>{var l;const{group:i,kind:s,type:c}=r,[o,d]=I(void 0),[u,m]=I(void 0);v(()=>{((o==null?void 0:o.kind)!==s||(o==null?void 0:o.type)!==c)&&d({kind:s,type:c})},[s,c,o]);const{data:p,isLoading:g}=Ae(i),y=(l=E(be).getOptionalBoolean("soundcheck.virtualizeOverviewPage"))!=null?l:!0,h=u||e,L=($,x)=>{$&&(d({kind:$,type:x}),x?a({...r,kind:$,type:x}):(r!=null&&r.hasOwnProperty("type")&&delete r.type,a({...r,kind:$})))},H=Ft();return t.createElement(C,{container:!0,spacing:0},t.createElement(C,{item:!0,xs:12},g?t.createElement(Ge,null):t.createElement(je,{unfilteredFacets:p,kind:o==null?void 0:o.kind,type:o==null?void 0:o.type,onChange:L})),t.createElement(C,{item:!0,xs:12,className:H.tableContainer},!g&&t.createElement(At,{facets:p,kind:o==null?void 0:o.kind,type:o==null?void 0:o.type,setError:m,hasError:h,ownerEntityRef:i,useVirtualizedResultsTable:y,isFixedGroup:n})))};export{Se as G,Bt as O,He as U,Z as a,ze as b,Y as c,Fe as u};
|
|
2
|
+
//# sourceMappingURL=OverviewPageContent-7cf86a3a.esm.js.map
|
package/dist/esm/{RefetchingIndicator-7160bb11.esm.js → RefetchingIndicator-b042ec49.esm.js}
RENAMED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import t,{useState as n}from"react";import{makeStyles as a,LinearProgress as m}from"@material-ui/core";import s from"react-use/lib/useDebounce";import"@backstage/catalog-model";import"@backstage/core-plugin-api";import{useIsFetching as c}from"@tanstack/react-query";import{F as d}from"./index-
|
|
2
|
-
//# sourceMappingURL=RefetchingIndicator-
|
|
1
|
+
import t,{useState as n}from"react";import{makeStyles as a,LinearProgress as m}from"@material-ui/core";import s from"react-use/lib/useDebounce";import"@backstage/catalog-model";import"@backstage/core-plugin-api";import{useIsFetching as c}from"@tanstack/react-query";import{F as d}from"./index-95ae147b.esm.js";import"@backstage/plugin-catalog-react";import"react-router-dom";const p=a(e=>({indicator:{position:"absolute",width:"100%",zIndex:e.zIndex.speedDial}})),l=()=>{const e=c(),i=p(),[r,o]=n(!!e);return s(()=>{o(!!e)},250,[e]),r?t.createElement(d,null,t.createElement("div",{className:i.indicator},t.createElement(m,{variant:"indeterminate","data-testid":"refetching-indicator"}))):null};export{l as R};
|
|
2
|
+
//# sourceMappingURL=RefetchingIndicator-b042ec49.esm.js.map
|