@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.
Files changed (223) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +232 -0
  3. package/config.d.ts +30 -0
  4. package/dist/App.esm.js +12 -0
  5. package/dist/App.esm.js.map +1 -0
  6. package/dist/api/index.esm.js +71 -0
  7. package/dist/api/index.esm.js.map +1 -0
  8. package/dist/assets/BulleyeIcon.esm.js +454 -0
  9. package/dist/assets/BulleyeIcon.esm.js.map +1 -0
  10. package/dist/assets/NoResultIcon.esm.js +146 -0
  11. package/dist/assets/NoResultIcon.esm.js.map +1 -0
  12. package/dist/assets/RiskIcon.esm.js +27 -0
  13. package/dist/assets/RiskIcon.esm.js.map +1 -0
  14. package/dist/assets/SettingIcon.esm.js +49 -0
  15. package/dist/assets/SettingIcon.esm.js.map +1 -0
  16. package/dist/assets/apiiroLogo/apiiroLogo.esm.js +21 -0
  17. package/dist/assets/apiiroLogo/apiiroLogo.esm.js.map +1 -0
  18. package/dist/assets/apiiroLogo/apiiroSidebar.esm.js +23 -0
  19. package/dist/assets/apiiroLogo/apiiroSidebar.esm.js.map +1 -0
  20. package/dist/assets/apiiroLogo/apiiroSmall.esm.js +19 -0
  21. package/dist/assets/apiiroLogo/apiiroSmall.esm.js.map +1 -0
  22. package/dist/assets/languageIcons/C.esm.js +7 -0
  23. package/dist/assets/languageIcons/C.esm.js.map +1 -0
  24. package/dist/assets/languageIcons/Cicd.esm.js +7 -0
  25. package/dist/assets/languageIcons/Cicd.esm.js.map +1 -0
  26. package/dist/assets/languageIcons/Clojure.esm.js +7 -0
  27. package/dist/assets/languageIcons/Clojure.esm.js.map +1 -0
  28. package/dist/assets/languageIcons/Cpp.esm.js +7 -0
  29. package/dist/assets/languageIcons/Cpp.esm.js.map +1 -0
  30. package/dist/assets/languageIcons/Csharp.esm.js +7 -0
  31. package/dist/assets/languageIcons/Csharp.esm.js.map +1 -0
  32. package/dist/assets/languageIcons/Dart.esm.js +7 -0
  33. package/dist/assets/languageIcons/Dart.esm.js.map +1 -0
  34. package/dist/assets/languageIcons/Go.esm.js +7 -0
  35. package/dist/assets/languageIcons/Go.esm.js.map +1 -0
  36. package/dist/assets/languageIcons/Groovy.esm.js +7 -0
  37. package/dist/assets/languageIcons/Groovy.esm.js.map +1 -0
  38. package/dist/assets/languageIcons/HTML.esm.js +7 -0
  39. package/dist/assets/languageIcons/HTML.esm.js.map +1 -0
  40. package/dist/assets/languageIcons/HclLanguage.esm.js +7 -0
  41. package/dist/assets/languageIcons/HclLanguage.esm.js.map +1 -0
  42. package/dist/assets/languageIcons/Java.esm.js +7 -0
  43. package/dist/assets/languageIcons/Java.esm.js.map +1 -0
  44. package/dist/assets/languageIcons/Javascript.esm.js +7 -0
  45. package/dist/assets/languageIcons/Javascript.esm.js.map +1 -0
  46. package/dist/assets/languageIcons/Kotlin.esm.js +7 -0
  47. package/dist/assets/languageIcons/Kotlin.esm.js.map +1 -0
  48. package/dist/assets/languageIcons/ObjectiveC.esm.js +7 -0
  49. package/dist/assets/languageIcons/ObjectiveC.esm.js.map +1 -0
  50. package/dist/assets/languageIcons/PHP.esm.js +7 -0
  51. package/dist/assets/languageIcons/PHP.esm.js.map +1 -0
  52. package/dist/assets/languageIcons/Perl.esm.js +13 -0
  53. package/dist/assets/languageIcons/Perl.esm.js.map +1 -0
  54. package/dist/assets/languageIcons/Python.esm.js +7 -0
  55. package/dist/assets/languageIcons/Python.esm.js.map +1 -0
  56. package/dist/assets/languageIcons/Ruby.esm.js +7 -0
  57. package/dist/assets/languageIcons/Ruby.esm.js.map +1 -0
  58. package/dist/assets/languageIcons/Rust.esm.js +7 -0
  59. package/dist/assets/languageIcons/Rust.esm.js.map +1 -0
  60. package/dist/assets/languageIcons/Scala.esm.js +7 -0
  61. package/dist/assets/languageIcons/Scala.esm.js.map +1 -0
  62. package/dist/assets/languageIcons/Swift.esm.js +7 -0
  63. package/dist/assets/languageIcons/Swift.esm.js.map +1 -0
  64. package/dist/assets/languageIcons/Terraform.esm.js +7 -0
  65. package/dist/assets/languageIcons/Terraform.esm.js.map +1 -0
  66. package/dist/assets/languageIcons/Typescript.esm.js +7 -0
  67. package/dist/assets/languageIcons/Typescript.esm.js.map +1 -0
  68. package/dist/assets/languageIcons/Unknown.esm.js +7 -0
  69. package/dist/assets/languageIcons/Unknown.esm.js.map +1 -0
  70. package/dist/assets/languageIcons/VB.esm.js +10 -0
  71. package/dist/assets/languageIcons/VB.esm.js.map +1 -0
  72. package/dist/assets/languageIcons/YAML.esm.js +7 -0
  73. package/dist/assets/languageIcons/YAML.esm.js.map +1 -0
  74. package/dist/assets/providerIcons/Azure.esm.js +7 -0
  75. package/dist/assets/providerIcons/Azure.esm.js.map +1 -0
  76. package/dist/assets/providerIcons/Bitbucket.esm.js +7 -0
  77. package/dist/assets/providerIcons/Bitbucket.esm.js.map +1 -0
  78. package/dist/assets/providerIcons/Gitlab.esm.js +7 -0
  79. package/dist/assets/providerIcons/Gitlab.esm.js.map +1 -0
  80. package/dist/components/ApiiroSidebar.esm.js +10 -0
  81. package/dist/components/ApiiroSidebar.esm.js.map +1 -0
  82. package/dist/components/ApplicationsList/ApplicationsList.esm.js +196 -0
  83. package/dist/components/ApplicationsList/ApplicationsList.esm.js.map +1 -0
  84. package/dist/components/CalendarDatePicker.esm.js +154 -0
  85. package/dist/components/CalendarDatePicker.esm.js.map +1 -0
  86. package/dist/components/CalendarDatePicker.styles.esm.js +198 -0
  87. package/dist/components/CalendarDatePicker.styles.esm.js.map +1 -0
  88. package/dist/components/Chip.esm.js +60 -0
  89. package/dist/components/Chip.esm.js.map +1 -0
  90. package/dist/components/ChipsList.esm.js +207 -0
  91. package/dist/components/ChipsList.esm.js.map +1 -0
  92. package/dist/components/ComponentDisplay.esm.js +42 -0
  93. package/dist/components/ComponentDisplay.esm.js.map +1 -0
  94. package/dist/components/DataGrid/CustomColumnMenu.esm.js +29 -0
  95. package/dist/components/DataGrid/CustomColumnMenu.esm.js.map +1 -0
  96. package/dist/components/DataGrid/CustomPagination.esm.js +113 -0
  97. package/dist/components/DataGrid/CustomPagination.esm.js.map +1 -0
  98. package/dist/components/DataGrid/CustomSearchToolbar.esm.js +117 -0
  99. package/dist/components/DataGrid/CustomSearchToolbar.esm.js.map +1 -0
  100. package/dist/components/DataGrid/DataGrid.esm.js +336 -0
  101. package/dist/components/DataGrid/DataGrid.esm.js.map +1 -0
  102. package/dist/components/DataGrid/PinColumnMenuItem.esm.js +24 -0
  103. package/dist/components/DataGrid/PinColumnMenuItem.esm.js.map +1 -0
  104. package/dist/components/DueDate.esm.js +34 -0
  105. package/dist/components/DueDate.esm.js.map +1 -0
  106. package/dist/components/Header.esm.js +27 -0
  107. package/dist/components/Header.esm.js.map +1 -0
  108. package/dist/components/MainContributors/MainContributors.esm.js +62 -0
  109. package/dist/components/MainContributors/MainContributors.esm.js.map +1 -0
  110. package/dist/components/MetricsGroup/TabMetricsGroup.esm.js +37 -0
  111. package/dist/components/MetricsGroup/TabMetricsGroup.esm.js.map +1 -0
  112. package/dist/components/MetricsGroup/WidgetMetricsGroup.esm.js +36 -0
  113. package/dist/components/MetricsGroup/WidgetMetricsGroup.esm.js.map +1 -0
  114. package/dist/components/RepositoryDisplay/RepositoryDisplay.esm.js +121 -0
  115. package/dist/components/RepositoryDisplay/RepositoryDisplay.esm.js.map +1 -0
  116. package/dist/components/RiskLevel.esm.js +88 -0
  117. package/dist/components/RiskLevel.esm.js.map +1 -0
  118. package/dist/components/RiskStatus.esm.js +58 -0
  119. package/dist/components/RiskStatus.esm.js.map +1 -0
  120. package/dist/components/SimpleTooltip.esm.js +24 -0
  121. package/dist/components/SimpleTooltip.esm.js.map +1 -0
  122. package/dist/components/SourcesDisplay.esm.js +47 -0
  123. package/dist/components/SourcesDisplay.esm.js.map +1 -0
  124. package/dist/components/TagsList/TagsList.esm.js +38 -0
  125. package/dist/components/TagsList/TagsList.esm.js.map +1 -0
  126. package/dist/components/TeamsDisplay.esm.js +47 -0
  127. package/dist/components/TeamsDisplay.esm.js.map +1 -0
  128. package/dist/components/charts/ColumnChart.esm.js +402 -0
  129. package/dist/components/charts/ColumnChart.esm.js.map +1 -0
  130. package/dist/components/charts/GaugeChart.esm.js +249 -0
  131. package/dist/components/charts/GaugeChart.esm.js.map +1 -0
  132. package/dist/components/charts/LineChart.esm.js +328 -0
  133. package/dist/components/charts/LineChart.esm.js.map +1 -0
  134. package/dist/components/charts/PieChart.esm.js +233 -0
  135. package/dist/components/charts/PieChart.esm.js.map +1 -0
  136. package/dist/components/common/ChartBox.esm.js +88 -0
  137. package/dist/components/common/ChartBox.esm.js.map +1 -0
  138. package/dist/components/common/CustomTooltip.esm.js +255 -0
  139. package/dist/components/common/CustomTooltip.esm.js.map +1 -0
  140. package/dist/components/common/ErrorSnackbar.esm.js +39 -0
  141. package/dist/components/common/ErrorSnackbar.esm.js.map +1 -0
  142. package/dist/components/common/NotFound.esm.js +30 -0
  143. package/dist/components/common/NotFound.esm.js.map +1 -0
  144. package/dist/components/common/SomethingWentWrong.esm.js +35 -0
  145. package/dist/components/common/SomethingWentWrong.esm.js.map +1 -0
  146. package/dist/components/common/languageIcons.esm.js +61 -0
  147. package/dist/components/common/languageIcons.esm.js.map +1 -0
  148. package/dist/components/common/logoSpinner.esm.js +28 -0
  149. package/dist/components/common/logoSpinner.esm.js.map +1 -0
  150. package/dist/components/common/scmProviders.esm.js +41 -0
  151. package/dist/components/common/scmProviders.esm.js.map +1 -0
  152. package/dist/components/filters/DiscoveredOnFilter.esm.js +284 -0
  153. package/dist/components/filters/DiscoveredOnFilter.esm.js.map +1 -0
  154. package/dist/components/filters/FilterDropdown.esm.js +325 -0
  155. package/dist/components/filters/FilterDropdown.esm.js.map +1 -0
  156. package/dist/components/filters/FilterDropdownClear.esm.js +45 -0
  157. package/dist/components/filters/FilterDropdownClear.esm.js.map +1 -0
  158. package/dist/components/filters/FilterDropdownList.esm.js +102 -0
  159. package/dist/components/filters/FilterDropdownList.esm.js.map +1 -0
  160. package/dist/components/filters/FilterDropdownSearch.esm.js +65 -0
  161. package/dist/components/filters/FilterDropdownSearch.esm.js.map +1 -0
  162. package/dist/components/filters/RiskInsightFilter.esm.js +579 -0
  163. package/dist/components/filters/RiskInsightFilter.esm.js.map +1 -0
  164. package/dist/components/tiles/MttrVsSLATile.esm.js +170 -0
  165. package/dist/components/tiles/MttrVsSLATile.esm.js.map +1 -0
  166. package/dist/components/tiles/RiskOverTimeTile.esm.js +311 -0
  167. package/dist/components/tiles/RiskOverTimeTile.esm.js.map +1 -0
  168. package/dist/components/tiles/SLAAdherenceTile.esm.js +115 -0
  169. package/dist/components/tiles/SLAAdherenceTile.esm.js.map +1 -0
  170. package/dist/components/tiles/StatusTile.esm.js +235 -0
  171. package/dist/components/tiles/StatusTile.esm.js.map +1 -0
  172. package/dist/components/tiles/TopLanguagesTile.esm.js +234 -0
  173. package/dist/components/tiles/TopLanguagesTile.esm.js.map +1 -0
  174. package/dist/components/tiles/TopRiskTile.esm.js +208 -0
  175. package/dist/components/tiles/TopRiskTile.esm.js.map +1 -0
  176. package/dist/hooks/useUrlFilters.esm.js +102 -0
  177. package/dist/hooks/useUrlFilters.esm.js.map +1 -0
  178. package/dist/index.d.ts +28 -0
  179. package/dist/index.esm.js +42 -0
  180. package/dist/index.esm.js.map +1 -0
  181. package/dist/pages/Repositories/Repositories.esm.js +102 -0
  182. package/dist/pages/Repositories/Repositories.esm.js.map +1 -0
  183. package/dist/pages/Repositories/tableConfig.esm.js +294 -0
  184. package/dist/pages/Repositories/tableConfig.esm.js.map +1 -0
  185. package/dist/pages/Risks/Risks.esm.js +258 -0
  186. package/dist/pages/Risks/Risks.esm.js.map +1 -0
  187. package/dist/pages/Risks/tableConfig.esm.js +305 -0
  188. package/dist/pages/Risks/tableConfig.esm.js.map +1 -0
  189. package/dist/pages/tab/Tab.esm.js +147 -0
  190. package/dist/pages/tab/Tab.esm.js.map +1 -0
  191. package/dist/pages/tab/TabProvider.esm.js +11 -0
  192. package/dist/pages/tab/TabProvider.esm.js.map +1 -0
  193. package/dist/pages/widget/Widget.esm.js +161 -0
  194. package/dist/pages/widget/Widget.esm.js.map +1 -0
  195. package/dist/pages/widget/WidgetProvider.esm.js +12 -0
  196. package/dist/pages/widget/WidgetProvider.esm.js.map +1 -0
  197. package/dist/plugin.esm.js +30 -0
  198. package/dist/plugin.esm.js.map +1 -0
  199. package/dist/queries/filterOptions.queries.esm.js +46 -0
  200. package/dist/queries/filterOptions.queries.esm.js.map +1 -0
  201. package/dist/queries/mttr-statistics.queries.esm.js +61 -0
  202. package/dist/queries/mttr-statistics.queries.esm.js.map +1 -0
  203. package/dist/queries/repository.queries.esm.js +60 -0
  204. package/dist/queries/repository.queries.esm.js.map +1 -0
  205. package/dist/queries/risk-score-over-time.queries.esm.js +61 -0
  206. package/dist/queries/risk-score-over-time.queries.esm.js.map +1 -0
  207. package/dist/queries/risks.queries.esm.js +65 -0
  208. package/dist/queries/risks.queries.esm.js.map +1 -0
  209. package/dist/queries/sla-breach.queries.esm.js +57 -0
  210. package/dist/queries/sla-breach.queries.esm.js.map +1 -0
  211. package/dist/queries/top-risks.queries.esm.js +47 -0
  212. package/dist/queries/top-risks.queries.esm.js.map +1 -0
  213. package/dist/routes.esm.js +8 -0
  214. package/dist/routes.esm.js.map +1 -0
  215. package/dist/theme/themeUtils.esm.js +290 -0
  216. package/dist/theme/themeUtils.esm.js.map +1 -0
  217. package/dist/utils/dateFormatter.esm.js +67 -0
  218. package/dist/utils/dateFormatter.esm.js.map +1 -0
  219. package/dist/utils/numberFormatter.esm.js +21 -0
  220. package/dist/utils/numberFormatter.esm.js.map +1 -0
  221. package/dist/utils/utils.esm.js +27 -0
  222. package/dist/utils/utils.esm.js.map +1 -0
  223. 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
+ ![Dashboard Repository List](../../assets/dashboard.png)
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
+ ![Apiiro Tab](../../assets/apiiro-tab.png)
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
+ ![Apiiro Widget](../../assets/apiiro-widget.png)
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
+ ![Apiiro Access Token](../../assets/access-token.png)
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
+ }
@@ -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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"}