@backstage-community/plugin-apiiro 0.1.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 +12 -0
- package/README.md +232 -0
- package/config.d.ts +30 -0
- package/dist/App.esm.js +12 -0
- package/dist/App.esm.js.map +1 -0
- package/dist/api/index.esm.js +71 -0
- package/dist/api/index.esm.js.map +1 -0
- package/dist/assets/BulleyeIcon.esm.js +454 -0
- package/dist/assets/BulleyeIcon.esm.js.map +1 -0
- package/dist/assets/NoResultIcon.esm.js +146 -0
- package/dist/assets/NoResultIcon.esm.js.map +1 -0
- package/dist/assets/RiskIcon.esm.js +27 -0
- package/dist/assets/RiskIcon.esm.js.map +1 -0
- package/dist/assets/SettingIcon.esm.js +49 -0
- package/dist/assets/SettingIcon.esm.js.map +1 -0
- package/dist/assets/apiiroLogo/apiiroLogo.esm.js +21 -0
- package/dist/assets/apiiroLogo/apiiroLogo.esm.js.map +1 -0
- package/dist/assets/apiiroLogo/apiiroSidebar.esm.js +23 -0
- package/dist/assets/apiiroLogo/apiiroSidebar.esm.js.map +1 -0
- package/dist/assets/apiiroLogo/apiiroSmall.esm.js +19 -0
- package/dist/assets/apiiroLogo/apiiroSmall.esm.js.map +1 -0
- package/dist/assets/languageIcons/C.esm.js +7 -0
- package/dist/assets/languageIcons/C.esm.js.map +1 -0
- package/dist/assets/languageIcons/Cicd.esm.js +7 -0
- package/dist/assets/languageIcons/Cicd.esm.js.map +1 -0
- package/dist/assets/languageIcons/Clojure.esm.js +7 -0
- package/dist/assets/languageIcons/Clojure.esm.js.map +1 -0
- package/dist/assets/languageIcons/Cpp.esm.js +7 -0
- package/dist/assets/languageIcons/Cpp.esm.js.map +1 -0
- package/dist/assets/languageIcons/Csharp.esm.js +7 -0
- package/dist/assets/languageIcons/Csharp.esm.js.map +1 -0
- package/dist/assets/languageIcons/Dart.esm.js +7 -0
- package/dist/assets/languageIcons/Dart.esm.js.map +1 -0
- package/dist/assets/languageIcons/Go.esm.js +7 -0
- package/dist/assets/languageIcons/Go.esm.js.map +1 -0
- package/dist/assets/languageIcons/Groovy.esm.js +7 -0
- package/dist/assets/languageIcons/Groovy.esm.js.map +1 -0
- package/dist/assets/languageIcons/HTML.esm.js +7 -0
- package/dist/assets/languageIcons/HTML.esm.js.map +1 -0
- package/dist/assets/languageIcons/HclLanguage.esm.js +7 -0
- package/dist/assets/languageIcons/HclLanguage.esm.js.map +1 -0
- package/dist/assets/languageIcons/Java.esm.js +7 -0
- package/dist/assets/languageIcons/Java.esm.js.map +1 -0
- package/dist/assets/languageIcons/Javascript.esm.js +7 -0
- package/dist/assets/languageIcons/Javascript.esm.js.map +1 -0
- package/dist/assets/languageIcons/Kotlin.esm.js +7 -0
- package/dist/assets/languageIcons/Kotlin.esm.js.map +1 -0
- package/dist/assets/languageIcons/ObjectiveC.esm.js +7 -0
- package/dist/assets/languageIcons/ObjectiveC.esm.js.map +1 -0
- package/dist/assets/languageIcons/PHP.esm.js +7 -0
- package/dist/assets/languageIcons/PHP.esm.js.map +1 -0
- package/dist/assets/languageIcons/Perl.esm.js +13 -0
- package/dist/assets/languageIcons/Perl.esm.js.map +1 -0
- package/dist/assets/languageIcons/Python.esm.js +7 -0
- package/dist/assets/languageIcons/Python.esm.js.map +1 -0
- package/dist/assets/languageIcons/Ruby.esm.js +7 -0
- package/dist/assets/languageIcons/Ruby.esm.js.map +1 -0
- package/dist/assets/languageIcons/Rust.esm.js +7 -0
- package/dist/assets/languageIcons/Rust.esm.js.map +1 -0
- package/dist/assets/languageIcons/Scala.esm.js +7 -0
- package/dist/assets/languageIcons/Scala.esm.js.map +1 -0
- package/dist/assets/languageIcons/Swift.esm.js +7 -0
- package/dist/assets/languageIcons/Swift.esm.js.map +1 -0
- package/dist/assets/languageIcons/Terraform.esm.js +7 -0
- package/dist/assets/languageIcons/Terraform.esm.js.map +1 -0
- package/dist/assets/languageIcons/Typescript.esm.js +7 -0
- package/dist/assets/languageIcons/Typescript.esm.js.map +1 -0
- package/dist/assets/languageIcons/Unknown.esm.js +7 -0
- package/dist/assets/languageIcons/Unknown.esm.js.map +1 -0
- package/dist/assets/languageIcons/VB.esm.js +10 -0
- package/dist/assets/languageIcons/VB.esm.js.map +1 -0
- package/dist/assets/languageIcons/YAML.esm.js +7 -0
- package/dist/assets/languageIcons/YAML.esm.js.map +1 -0
- package/dist/assets/providerIcons/Azure.esm.js +7 -0
- package/dist/assets/providerIcons/Azure.esm.js.map +1 -0
- package/dist/assets/providerIcons/Bitbucket.esm.js +7 -0
- package/dist/assets/providerIcons/Bitbucket.esm.js.map +1 -0
- package/dist/assets/providerIcons/Gitlab.esm.js +7 -0
- package/dist/assets/providerIcons/Gitlab.esm.js.map +1 -0
- package/dist/components/ApiiroSidebar.esm.js +10 -0
- package/dist/components/ApiiroSidebar.esm.js.map +1 -0
- package/dist/components/ApplicationsList/ApplicationsList.esm.js +196 -0
- package/dist/components/ApplicationsList/ApplicationsList.esm.js.map +1 -0
- package/dist/components/CalendarDatePicker.esm.js +154 -0
- package/dist/components/CalendarDatePicker.esm.js.map +1 -0
- package/dist/components/CalendarDatePicker.styles.esm.js +198 -0
- package/dist/components/CalendarDatePicker.styles.esm.js.map +1 -0
- package/dist/components/Chip.esm.js +60 -0
- package/dist/components/Chip.esm.js.map +1 -0
- package/dist/components/ChipsList.esm.js +207 -0
- package/dist/components/ChipsList.esm.js.map +1 -0
- package/dist/components/ComponentDisplay.esm.js +42 -0
- package/dist/components/ComponentDisplay.esm.js.map +1 -0
- package/dist/components/DataGrid/CustomColumnMenu.esm.js +29 -0
- package/dist/components/DataGrid/CustomColumnMenu.esm.js.map +1 -0
- package/dist/components/DataGrid/CustomPagination.esm.js +113 -0
- package/dist/components/DataGrid/CustomPagination.esm.js.map +1 -0
- package/dist/components/DataGrid/CustomSearchToolbar.esm.js +117 -0
- package/dist/components/DataGrid/CustomSearchToolbar.esm.js.map +1 -0
- package/dist/components/DataGrid/DataGrid.esm.js +336 -0
- package/dist/components/DataGrid/DataGrid.esm.js.map +1 -0
- package/dist/components/DataGrid/PinColumnMenuItem.esm.js +24 -0
- package/dist/components/DataGrid/PinColumnMenuItem.esm.js.map +1 -0
- package/dist/components/DueDate.esm.js +34 -0
- package/dist/components/DueDate.esm.js.map +1 -0
- package/dist/components/Header.esm.js +27 -0
- package/dist/components/Header.esm.js.map +1 -0
- package/dist/components/MainContributors/MainContributors.esm.js +62 -0
- package/dist/components/MainContributors/MainContributors.esm.js.map +1 -0
- package/dist/components/MetricsGroup/TabMetricsGroup.esm.js +37 -0
- package/dist/components/MetricsGroup/TabMetricsGroup.esm.js.map +1 -0
- package/dist/components/MetricsGroup/WidgetMetricsGroup.esm.js +36 -0
- package/dist/components/MetricsGroup/WidgetMetricsGroup.esm.js.map +1 -0
- package/dist/components/RepositoryDisplay/RepositoryDisplay.esm.js +121 -0
- package/dist/components/RepositoryDisplay/RepositoryDisplay.esm.js.map +1 -0
- package/dist/components/RiskLevel.esm.js +88 -0
- package/dist/components/RiskLevel.esm.js.map +1 -0
- package/dist/components/RiskStatus.esm.js +58 -0
- package/dist/components/RiskStatus.esm.js.map +1 -0
- package/dist/components/SimpleTooltip.esm.js +24 -0
- package/dist/components/SimpleTooltip.esm.js.map +1 -0
- package/dist/components/SourcesDisplay.esm.js +47 -0
- package/dist/components/SourcesDisplay.esm.js.map +1 -0
- package/dist/components/TagsList/TagsList.esm.js +38 -0
- package/dist/components/TagsList/TagsList.esm.js.map +1 -0
- package/dist/components/TeamsDisplay.esm.js +47 -0
- package/dist/components/TeamsDisplay.esm.js.map +1 -0
- package/dist/components/charts/ColumnChart.esm.js +402 -0
- package/dist/components/charts/ColumnChart.esm.js.map +1 -0
- package/dist/components/charts/GaugeChart.esm.js +249 -0
- package/dist/components/charts/GaugeChart.esm.js.map +1 -0
- package/dist/components/charts/LineChart.esm.js +328 -0
- package/dist/components/charts/LineChart.esm.js.map +1 -0
- package/dist/components/charts/PieChart.esm.js +233 -0
- package/dist/components/charts/PieChart.esm.js.map +1 -0
- package/dist/components/common/ChartBox.esm.js +88 -0
- package/dist/components/common/ChartBox.esm.js.map +1 -0
- package/dist/components/common/CustomTooltip.esm.js +255 -0
- package/dist/components/common/CustomTooltip.esm.js.map +1 -0
- package/dist/components/common/ErrorSnackbar.esm.js +39 -0
- package/dist/components/common/ErrorSnackbar.esm.js.map +1 -0
- package/dist/components/common/NotFound.esm.js +30 -0
- package/dist/components/common/NotFound.esm.js.map +1 -0
- package/dist/components/common/SomethingWentWrong.esm.js +35 -0
- package/dist/components/common/SomethingWentWrong.esm.js.map +1 -0
- package/dist/components/common/languageIcons.esm.js +61 -0
- package/dist/components/common/languageIcons.esm.js.map +1 -0
- package/dist/components/common/logoSpinner.esm.js +28 -0
- package/dist/components/common/logoSpinner.esm.js.map +1 -0
- package/dist/components/common/scmProviders.esm.js +41 -0
- package/dist/components/common/scmProviders.esm.js.map +1 -0
- package/dist/components/filters/DiscoveredOnFilter.esm.js +284 -0
- package/dist/components/filters/DiscoveredOnFilter.esm.js.map +1 -0
- package/dist/components/filters/FilterDropdown.esm.js +325 -0
- package/dist/components/filters/FilterDropdown.esm.js.map +1 -0
- package/dist/components/filters/FilterDropdownClear.esm.js +45 -0
- package/dist/components/filters/FilterDropdownClear.esm.js.map +1 -0
- package/dist/components/filters/FilterDropdownList.esm.js +102 -0
- package/dist/components/filters/FilterDropdownList.esm.js.map +1 -0
- package/dist/components/filters/FilterDropdownSearch.esm.js +65 -0
- package/dist/components/filters/FilterDropdownSearch.esm.js.map +1 -0
- package/dist/components/filters/RiskInsightFilter.esm.js +579 -0
- package/dist/components/filters/RiskInsightFilter.esm.js.map +1 -0
- package/dist/components/tiles/MttrVsSLATile.esm.js +170 -0
- package/dist/components/tiles/MttrVsSLATile.esm.js.map +1 -0
- package/dist/components/tiles/RiskOverTimeTile.esm.js +311 -0
- package/dist/components/tiles/RiskOverTimeTile.esm.js.map +1 -0
- package/dist/components/tiles/SLAAdherenceTile.esm.js +115 -0
- package/dist/components/tiles/SLAAdherenceTile.esm.js.map +1 -0
- package/dist/components/tiles/StatusTile.esm.js +235 -0
- package/dist/components/tiles/StatusTile.esm.js.map +1 -0
- package/dist/components/tiles/TopLanguagesTile.esm.js +234 -0
- package/dist/components/tiles/TopLanguagesTile.esm.js.map +1 -0
- package/dist/components/tiles/TopRiskTile.esm.js +208 -0
- package/dist/components/tiles/TopRiskTile.esm.js.map +1 -0
- package/dist/hooks/useUrlFilters.esm.js +102 -0
- package/dist/hooks/useUrlFilters.esm.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.esm.js +42 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/pages/Repositories/Repositories.esm.js +102 -0
- package/dist/pages/Repositories/Repositories.esm.js.map +1 -0
- package/dist/pages/Repositories/tableConfig.esm.js +294 -0
- package/dist/pages/Repositories/tableConfig.esm.js.map +1 -0
- package/dist/pages/Risks/Risks.esm.js +258 -0
- package/dist/pages/Risks/Risks.esm.js.map +1 -0
- package/dist/pages/Risks/tableConfig.esm.js +305 -0
- package/dist/pages/Risks/tableConfig.esm.js.map +1 -0
- package/dist/pages/tab/Tab.esm.js +147 -0
- package/dist/pages/tab/Tab.esm.js.map +1 -0
- package/dist/pages/tab/TabProvider.esm.js +11 -0
- package/dist/pages/tab/TabProvider.esm.js.map +1 -0
- package/dist/pages/widget/Widget.esm.js +161 -0
- package/dist/pages/widget/Widget.esm.js.map +1 -0
- package/dist/pages/widget/WidgetProvider.esm.js +12 -0
- package/dist/pages/widget/WidgetProvider.esm.js.map +1 -0
- package/dist/plugin.esm.js +30 -0
- package/dist/plugin.esm.js.map +1 -0
- package/dist/queries/filterOptions.queries.esm.js +46 -0
- package/dist/queries/filterOptions.queries.esm.js.map +1 -0
- package/dist/queries/mttr-statistics.queries.esm.js +61 -0
- package/dist/queries/mttr-statistics.queries.esm.js.map +1 -0
- package/dist/queries/repository.queries.esm.js +60 -0
- package/dist/queries/repository.queries.esm.js.map +1 -0
- package/dist/queries/risk-score-over-time.queries.esm.js +61 -0
- package/dist/queries/risk-score-over-time.queries.esm.js.map +1 -0
- package/dist/queries/risks.queries.esm.js +65 -0
- package/dist/queries/risks.queries.esm.js.map +1 -0
- package/dist/queries/sla-breach.queries.esm.js +57 -0
- package/dist/queries/sla-breach.queries.esm.js.map +1 -0
- package/dist/queries/top-risks.queries.esm.js +47 -0
- package/dist/queries/top-risks.queries.esm.js.map +1 -0
- package/dist/routes.esm.js +8 -0
- package/dist/routes.esm.js.map +1 -0
- package/dist/theme/themeUtils.esm.js +290 -0
- package/dist/theme/themeUtils.esm.js.map +1 -0
- package/dist/utils/dateFormatter.esm.js +67 -0
- package/dist/utils/dateFormatter.esm.js.map +1 -0
- package/dist/utils/numberFormatter.esm.js +21 -0
- package/dist/utils/numberFormatter.esm.js.map +1 -0
- package/dist/utils/utils.esm.js +27 -0
- package/dist/utils/utils.esm.js.map +1 -0
- package/package.json +90 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# @backstage-community/plugin-apiiro
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 8407557: Added new [Apiiro](https://apiiro.com/) plugin. Check out the plugins [README.md](https://github.com/backstage/community-plugins/tree/main/workspaces/apiiro/plugins/apiiro) for more details!
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [8407557]
|
|
12
|
+
- @backstage-community/plugin-apiiro-common@0.1.0
|
package/README.md
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# Apiiro Plugin for Backstage
|
|
2
|
+
|
|
3
|
+
The Apiiro plugin for Backstage integrates Apiiro's application risk management capabilities directly into your Backstage developer portal. This plugin empowers developers to code securely by automatically checking for security vulnerabilities and enables them to review and address newly introduced vulnerabilities directly in Backstage.
|
|
4
|
+
|
|
5
|
+
## Plugin Compatibility
|
|
6
|
+
|
|
7
|
+
The plugin has been successfully tested with Backstage v1.44.0 If you are using a newer version of Backstage, please file an issue, and we will provide guidance on the best integration practices for your specific version.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **Dashboard View**: Repository list with statistics sourced from Apiiro
|
|
12
|
+
- **Apiiro Tab**: In-depth view of repository open risks and detailed metrics
|
|
13
|
+
- **Apiiro Widget**: High-level overview widget that can be embedded in custom entity tabs
|
|
14
|
+
- **Permission Control**: Conditional permissions for fine-grained access control to Apiiro metrics
|
|
15
|
+
|
|
16
|
+
## Views
|
|
17
|
+
|
|
18
|
+
### Dashboard – Repository List
|
|
19
|
+
|
|
20
|
+
Displays the list of integrated repositories along with statistics sourced from Apiiro. Clicking on a repository redirects you to the Apiiro tab for detailed insights.
|
|
21
|
+
|
|
22
|
+

|
|
23
|
+
|
|
24
|
+
### Apiiro Tab
|
|
25
|
+
|
|
26
|
+
Provides an in-depth look at each repository's open risks and detailed metrics retrieved from Apiiro.
|
|
27
|
+
|
|
28
|
+

|
|
29
|
+
|
|
30
|
+
### Apiiro Widget
|
|
31
|
+
|
|
32
|
+
Offers a high-level overview of the repository, including programming languages and top risk details. Can be added to any custom entity tab.
|
|
33
|
+
|
|
34
|
+

|
|
35
|
+
|
|
36
|
+
## Prerequisites
|
|
37
|
+
|
|
38
|
+
- The entity for a repository must be present within Backstage to see Apiiro results
|
|
39
|
+
- Appropriate access permissions to an entity in Backstage are required to view its Apiiro results
|
|
40
|
+
- An Apiiro Access Token with at least read permissions
|
|
41
|
+
|
|
42
|
+
### Dependencies
|
|
43
|
+
|
|
44
|
+
> [!IMPORTANT]
|
|
45
|
+
> Please note that the frontend plugin will not function without the backend plugin.
|
|
46
|
+
|
|
47
|
+
## Getting Started
|
|
48
|
+
|
|
49
|
+
### 1. Configure Apiiro Plugin for Backstage
|
|
50
|
+
|
|
51
|
+
Add the following annotation into your catalog.
|
|
52
|
+
To be able to use the Apiiro plugin you need to add the following annotation to any entities you want to use it with:
|
|
53
|
+
|
|
54
|
+
```yaml
|
|
55
|
+
apiiro.com/repo-id: <apiiro-repo-key>
|
|
56
|
+
apiiro.com/allow-metrics-view: "true" or "false" (controls whether the Metrics view appears in the Apiiro tab and Apiiro widget)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Let's break this down a little: `<apiiro-repo-key>` will be the key of your repository in Apiiro.
|
|
60
|
+
|
|
61
|
+
Here's what that will look like in action:
|
|
62
|
+
|
|
63
|
+
```yaml
|
|
64
|
+
# Example catalog-info.yaml entity definition file
|
|
65
|
+
apiVersion: backstage.io/v1alpha1
|
|
66
|
+
kind: Component
|
|
67
|
+
metadata:
|
|
68
|
+
name: my-component
|
|
69
|
+
annotations:
|
|
70
|
+
apiiro.com/repo-id: my-repo-key
|
|
71
|
+
apiiro.com/allow-metrics-view: 'true'
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Please find the steps to add the annotation automatically [here](../apiiro-backend/README.md#automatically-adding-apiiro-annotations-optional).
|
|
75
|
+
|
|
76
|
+
### 2. Install required plugins packages
|
|
77
|
+
|
|
78
|
+
From your Backstage root directory, run:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
yarn --cwd packages/app add @backstage-community/plugin-apiiro
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Note:** The Backstage frontend plugin will not function without the backend plugin. Please find the steps to add the backend plugin [here](../apiiro-backend/README.md#installation).
|
|
85
|
+
|
|
86
|
+
### 3. Configuration
|
|
87
|
+
|
|
88
|
+
Add your Apiiro Access Token to your `app-config.yaml` or `app-config.production.yaml`:
|
|
89
|
+
|
|
90
|
+
```yaml
|
|
91
|
+
apiiro:
|
|
92
|
+
accessToken: ${APIIRO_TOKEN}
|
|
93
|
+
defaultAllowMetricsView: true
|
|
94
|
+
# Optional: Configure default risk filters for the Apiiro Risk Table (Example configuration)
|
|
95
|
+
defaultRiskFilters:
|
|
96
|
+
RiskLevel:
|
|
97
|
+
- Critical
|
|
98
|
+
- High
|
|
99
|
+
RiskInsight:
|
|
100
|
+
- Internet exposed
|
|
101
|
+
- Deployed
|
|
102
|
+
RiskCategory:
|
|
103
|
+
- SAST findings
|
|
104
|
+
- Secrets
|
|
105
|
+
Provider:
|
|
106
|
+
- ApiiroSca
|
|
107
|
+
- AkamaiApiSecurity
|
|
108
|
+
PolicyTags:
|
|
109
|
+
- Security Code Review
|
|
110
|
+
- Compliance Review (PCI)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Where:
|
|
114
|
+
|
|
115
|
+
- `accessToken` is your Apiiro Access Token
|
|
116
|
+
- `defaultAllowMetricsView` is a boolean value that controls whether the Metrics view appears in the Apiiro Tab and Apiiro Widget by default. If annotation is not set, this value will be used. Default value is `true`.
|
|
117
|
+
- `defaultRiskFilters` (optional) configures default filters for the Apiiro Risk Table. Please refer to the [backend documentation](../apiiro-backend/README.md#configure-default-risk-filters-optional) for more details.
|
|
118
|
+
|
|
119
|
+
**How to Retrieve an Access Token from Apiiro:**
|
|
120
|
+
|
|
121
|
+
1. Log in to your Apiiro instance
|
|
122
|
+
2. Go to Settings → Access Token
|
|
123
|
+
3. Create a new Access Token with a long expiration period (1 year) and grant at least read permissions
|
|
124
|
+
4. Generate and securely save the token
|
|
125
|
+
|
|
126
|
+

|
|
127
|
+
|
|
128
|
+
### 4. Add Apiiro Tab to Entity Page
|
|
129
|
+
|
|
130
|
+
In `packages/app/src/components/Catalog/EntityPage.tsx`:
|
|
131
|
+
|
|
132
|
+
```tsx
|
|
133
|
+
// Import the Apiiro tab
|
|
134
|
+
import {
|
|
135
|
+
ApiiroTab,
|
|
136
|
+
isApiiroRepoAvailable,
|
|
137
|
+
} from '@backstage-community/plugin-apiiro';
|
|
138
|
+
|
|
139
|
+
// Add the route to your service entity page
|
|
140
|
+
const serviceEntityPage = (
|
|
141
|
+
<EntityLayout>
|
|
142
|
+
<EntityLayout.Route path="/" title="Overview">
|
|
143
|
+
{/* ... other elements */}
|
|
144
|
+
</EntityLayout.Route>
|
|
145
|
+
|
|
146
|
+
<EntityLayout.Route
|
|
147
|
+
if={isApiiroRepoAvailable}
|
|
148
|
+
path="/apiiro"
|
|
149
|
+
title="Apiiro"
|
|
150
|
+
>
|
|
151
|
+
<ApiiroTab />
|
|
152
|
+
</EntityLayout.Route>
|
|
153
|
+
|
|
154
|
+
{/* ... other elements */}
|
|
155
|
+
</EntityLayout>
|
|
156
|
+
);
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### 5. Add the Apiiro Sidebar with Repositories List (Optional)
|
|
160
|
+
|
|
161
|
+
In `packages/app/src/App.tsx`:
|
|
162
|
+
|
|
163
|
+
```tsx
|
|
164
|
+
// Import the Apiiro page
|
|
165
|
+
import { ApiiroPage } from '@backstage-community/plugin-apiiro';
|
|
166
|
+
|
|
167
|
+
// Add the route
|
|
168
|
+
const routes = (
|
|
169
|
+
<FlatRoutes>
|
|
170
|
+
<Route path="/" element={<Navigate to="catalog" />} />
|
|
171
|
+
<Route path="/catalog" element={<CatalogIndexPage />} />
|
|
172
|
+
{/* ... other elements */}
|
|
173
|
+
<Route path="/apiiro" element={<ApiiroPage />} />
|
|
174
|
+
{/* ... other elements */}
|
|
175
|
+
</FlatRoutes>
|
|
176
|
+
);
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Add Apiiro Sidebar Button
|
|
180
|
+
|
|
181
|
+
In `packages/app/src/components/Root/Root.tsx`:
|
|
182
|
+
|
|
183
|
+
```tsx
|
|
184
|
+
// Import the Apiiro sidebar
|
|
185
|
+
import { ApiiroSidebar } from '@backstage-community/plugin-apiiro';
|
|
186
|
+
|
|
187
|
+
// Add to your sidebar
|
|
188
|
+
export const Root = ({ children }: PropsWithChildren<{}>) => (
|
|
189
|
+
<SidebarPage>
|
|
190
|
+
<Sidebar>
|
|
191
|
+
{/* ... other elements */}
|
|
192
|
+
|
|
193
|
+
<ApiiroSidebar />
|
|
194
|
+
|
|
195
|
+
{/* ... other elements */}
|
|
196
|
+
</Sidebar>
|
|
197
|
+
{children}
|
|
198
|
+
</SidebarPage>
|
|
199
|
+
);
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### 6. Add Apiiro Widget to Custom Entity Tab (Optional)
|
|
203
|
+
|
|
204
|
+
The Apiiro plugin for Backstage includes a widget that can be embedded in a custom tab of the Backstage entity. This widget provides an overview of the risk associated with that entity, alongside your other valuable insights.
|
|
205
|
+
To add the widget, include the following component in your custom entity tab:
|
|
206
|
+
|
|
207
|
+
```tsx
|
|
208
|
+
// ... other imports here
|
|
209
|
+
import {
|
|
210
|
+
ApiiroWidget,
|
|
211
|
+
isApiiroRepoAvailable,
|
|
212
|
+
} from '@backstage-community/plugin-apiiro';
|
|
213
|
+
// ... other components
|
|
214
|
+
|
|
215
|
+
// add the following line to import the component at required position
|
|
216
|
+
<EntitySwitch>
|
|
217
|
+
<EntitySwitch.Case if={isApiiroRepoAvailable}>
|
|
218
|
+
<Grid item md={12} xs={12}>
|
|
219
|
+
<ApiiroWidget />
|
|
220
|
+
</Grid>
|
|
221
|
+
</EntitySwitch.Case>
|
|
222
|
+
</EntitySwitch>;
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## Development
|
|
226
|
+
|
|
227
|
+
To run the entire project including the backend, run `yarn start` from the workspace root directory.
|
|
228
|
+
|
|
229
|
+
## Links
|
|
230
|
+
|
|
231
|
+
- [Backend Plugin Documentation](../apiiro-backend/README.md)
|
|
232
|
+
- [Add Annotation Automatically](../apiiro-backend/README.md#automatically-adding-apiiro-annotations-optional)
|
package/config.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 The Backstage Authors
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
export interface Config {
|
|
18
|
+
/**
|
|
19
|
+
* Apiiro plugin configuration.
|
|
20
|
+
* @visibility frontend
|
|
21
|
+
*/
|
|
22
|
+
apiiro?: {
|
|
23
|
+
/**
|
|
24
|
+
* Default value for the allow metrics view annotation
|
|
25
|
+
* @visibility frontend
|
|
26
|
+
* @default true
|
|
27
|
+
*/
|
|
28
|
+
defaultAllowMetricsView?: boolean;
|
|
29
|
+
};
|
|
30
|
+
}
|
package/dist/App.esm.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { Routes, Route } from 'react-router-dom';
|
|
3
|
+
import { Repositories } from './pages/Repositories/Repositories.esm.js';
|
|
4
|
+
import { QueryClientProvider } from '@tanstack/react-query';
|
|
5
|
+
import { queryClient } from './api/index.esm.js';
|
|
6
|
+
|
|
7
|
+
const App = () => {
|
|
8
|
+
return /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsx(Routes, { children: /* @__PURE__ */ jsx(Route, { path: "/", element: /* @__PURE__ */ jsx(Repositories, {}) }) }) });
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export { App };
|
|
12
|
+
//# sourceMappingURL=App.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"App.esm.js","sources":["../src/App.tsx"],"sourcesContent":["/*\n * Copyright 2025 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 { Routes, Route } from 'react-router-dom';\nimport { Repositories } from './pages/Repositories';\nimport { QueryClientProvider } from '@tanstack/react-query';\nimport { queryClient } from './api';\n\nexport const App = () => {\n return (\n <QueryClientProvider client={queryClient}>\n <Routes>\n <Route path=\"/\" element={<Repositories />} />\n </Routes>\n </QueryClientProvider>\n );\n};\n"],"names":[],"mappings":";;;;;;AAoBO,MAAM,MAAM,MAAM;AACvB,EAAA,uBACE,GAAA,CAAC,mBAAA,EAAA,EAAoB,MAAA,EAAQ,WAAA,EAC3B,8BAAC,MAAA,EAAA,EACC,QAAA,kBAAA,GAAA,CAAC,KAAA,EAAA,EAAM,IAAA,EAAK,KAAI,OAAA,kBAAS,GAAA,CAAC,YAAA,EAAA,EAAa,CAAA,EAAI,GAC7C,CAAA,EACF,CAAA;AAEJ;;;;"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { QueryClient } from '@tanstack/react-query';
|
|
2
|
+
import { createApiRef } from '@backstage/core-plugin-api';
|
|
3
|
+
|
|
4
|
+
const apiiroApiRef = createApiRef({
|
|
5
|
+
id: "plugin.apiiro.service"
|
|
6
|
+
});
|
|
7
|
+
class ApiiroClient {
|
|
8
|
+
discoveryApi;
|
|
9
|
+
configApi;
|
|
10
|
+
constructor(options) {
|
|
11
|
+
this.discoveryApi = options.discoveryApi;
|
|
12
|
+
this.configApi = options.configApi;
|
|
13
|
+
}
|
|
14
|
+
getDefaultAllowMetricsView() {
|
|
15
|
+
return this.configApi.getOptionalBoolean("apiiro.defaultAllowMetricsView") ?? true;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const queryClient = new QueryClient();
|
|
19
|
+
function assembleUri(uri, params) {
|
|
20
|
+
if (!params) {
|
|
21
|
+
return uri;
|
|
22
|
+
}
|
|
23
|
+
const queryString = new URLSearchParams(params).toString();
|
|
24
|
+
return `${uri}?${queryString}`;
|
|
25
|
+
}
|
|
26
|
+
function buildHeaders(optionHeaders) {
|
|
27
|
+
const headers = new Headers();
|
|
28
|
+
headers.set("Content-Type" /* CONTENT_TYPE */, "application/json");
|
|
29
|
+
Object.keys(optionHeaders).forEach((header) => {
|
|
30
|
+
const headerValue = optionHeaders[header];
|
|
31
|
+
if (headerValue) {
|
|
32
|
+
headers.set(header, headerValue);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
return headers;
|
|
36
|
+
}
|
|
37
|
+
function fetchRequest(fetchApi, method, url, opts) {
|
|
38
|
+
const { params, body, headers, signal } = opts;
|
|
39
|
+
const requestURL = params ? assembleUri(url, params) : url;
|
|
40
|
+
const requestParams = {
|
|
41
|
+
headers: buildHeaders(headers || {}),
|
|
42
|
+
method,
|
|
43
|
+
signal
|
|
44
|
+
};
|
|
45
|
+
if (body) {
|
|
46
|
+
requestParams.body = typeof body === "string" ? body : JSON.stringify(body);
|
|
47
|
+
}
|
|
48
|
+
return fetchApi(requestURL, requestParams);
|
|
49
|
+
}
|
|
50
|
+
function toJson(response) {
|
|
51
|
+
if (response.status === 204 || response.body === null) {
|
|
52
|
+
return Promise.resolve({});
|
|
53
|
+
}
|
|
54
|
+
return response.json().then((json) => {
|
|
55
|
+
return response.ok ? json : Promise.reject(json);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
const defaultOpts = {
|
|
59
|
+
body: null,
|
|
60
|
+
headers: {},
|
|
61
|
+
params: null
|
|
62
|
+
};
|
|
63
|
+
function get(fetchApi, url, opts = defaultOpts) {
|
|
64
|
+
return fetchRequest(fetchApi, "GET" /* GET */, url, opts).then(toJson);
|
|
65
|
+
}
|
|
66
|
+
function post(fetchApi, url, opts = defaultOpts) {
|
|
67
|
+
return fetchRequest(fetchApi, "POST" /* POST */, url, opts).then(toJson);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export { ApiiroClient, apiiroApiRef, get, post, queryClient };
|
|
71
|
+
//# sourceMappingURL=index.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":["../../src/api/index.ts"],"sourcesContent":["/*\n * Copyright 2024 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 { QueryClient } from '@tanstack/react-query';\nimport {\n ConfigApi,\n createApiRef,\n DiscoveryApi,\n} from '@backstage/core-plugin-api';\n\n/**\n * Plugin API\n */\nexport type ApiiroApi = {\n discoveryApi: DiscoveryApi;\n getDefaultAllowMetricsView: () => boolean;\n};\n\nexport const apiiroApiRef = createApiRef<ApiiroApi>({\n id: 'plugin.apiiro.service',\n});\n\nexport class ApiiroClient implements ApiiroApi {\n discoveryApi: DiscoveryApi;\n private readonly configApi: ConfigApi;\n\n constructor(options: { discoveryApi: DiscoveryApi; configApi: ConfigApi }) {\n this.discoveryApi = options.discoveryApi;\n this.configApi = options.configApi;\n }\n\n getDefaultAllowMetricsView(): boolean {\n return (\n this.configApi.getOptionalBoolean('apiiro.defaultAllowMetricsView') ??\n true\n );\n }\n}\n\n/**\n * React Query Client\n */\nexport const queryClient = new QueryClient();\n\n/**\n * Fetch: GET, POST\n */\ntype QueryParams = Record<string, string>;\n\ntype RequestHeaders = Record<string, string>;\n\nenum ApiHeaders {\n CONTENT_TYPE = 'Content-Type',\n}\n\nenum REQUEST_METHOD {\n GET = 'GET',\n POST = 'POST',\n}\n\ninterface RequestOptions {\n body?: any;\n headers?: RequestHeaders;\n params?: Record<string, any> | null;\n signal?: AbortSignal;\n}\n\nfunction assembleUri(uri: string, params?: QueryParams): string {\n if (!params) {\n return uri;\n }\n\n const queryString = new URLSearchParams(params).toString();\n return `${uri}?${queryString}`;\n}\n\nfunction buildHeaders(optionHeaders: RequestHeaders): Headers {\n const headers = new Headers();\n headers.set(ApiHeaders.CONTENT_TYPE, 'application/json');\n\n Object.keys(optionHeaders).forEach(header => {\n const headerValue = optionHeaders[header];\n if (headerValue) {\n headers.set(header, headerValue);\n }\n });\n\n return headers;\n}\n\nfunction fetchRequest(\n fetchApi: typeof fetch,\n method: REQUEST_METHOD,\n url: string,\n opts: RequestOptions,\n): Promise<any> {\n const { params, body, headers, signal } = opts;\n\n const requestURL = params ? assembleUri(url, params) : url;\n\n const requestParams: RequestInit = {\n headers: buildHeaders(headers || {}),\n method,\n signal,\n };\n\n if (body) {\n requestParams.body = typeof body === 'string' ? body : JSON.stringify(body);\n }\n\n return fetchApi(requestURL, requestParams);\n}\n\nfunction toJson(response: Response): Promise<any> {\n if (response.status === 204 || response.body === null) {\n return Promise.resolve({});\n }\n\n return response.json().then(json => {\n return response.ok ? json : Promise.reject(json);\n });\n}\n\nconst defaultOpts: RequestOptions = {\n body: null,\n headers: {},\n params: null,\n};\n\nexport function get<T>(\n fetchApi: typeof fetch,\n url: string,\n opts: RequestOptions = defaultOpts,\n): Promise<T> {\n return fetchRequest(fetchApi, REQUEST_METHOD.GET, url, opts).then(toJson);\n}\n\nexport function post<T>(\n fetchApi: typeof fetch,\n url: string,\n opts: RequestOptions = defaultOpts,\n): Promise<T> {\n return fetchRequest(fetchApi, REQUEST_METHOD.POST, url, opts).then(toJson);\n}\n"],"names":[],"mappings":"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"}
|