@axis-backstage/plugin-jira-dashboard-backend 2.0.0 → 2.2.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/README.md +54 -3
- package/config.d.ts +1 -1
- package/dist/index.cjs.js +82 -47
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +18 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -25,16 +25,16 @@ The Jira Dashboard plugin requires the following YAML to be added to your app-co
|
|
|
25
25
|
jiraDashboard:
|
|
26
26
|
token: ${JIRA_TOKEN}
|
|
27
27
|
baseUrl: ${JIRA_BASE_URL}
|
|
28
|
-
userEmailSuffix: ${JIRA_EMAIL_SUFFIX}
|
|
28
|
+
userEmailSuffix: ${JIRA_EMAIL_SUFFIX} # Optional
|
|
29
29
|
annotationPrefix: ${JIRA_ANNOTATION_PREFIX} # Optional
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
#### Configuration Details:
|
|
33
33
|
|
|
34
|
-
- `JIRA_TOKEN`: The
|
|
34
|
+
- `JIRA_TOKEN`: The "Authorization" header used for Jira authentication.
|
|
35
35
|
> Note: The JIRA_TOKEN variable from [Roadie's Backstage Jira plugin](https://roadie.io/backstage/plugins/jira) can not be reused here because of the added encoding in this token.
|
|
36
36
|
- `JIRA_BASE_URL`: The base url for Jira in your company, including the API version. For instance: https://jira.se.your-company.com/rest/api/2/
|
|
37
|
-
- `JIRA_EMAIL_SUFFIX`:
|
|
37
|
+
- `JIRA_EMAIL_SUFFIX`: Optional email suffix used for retrieving a specific Jira user in a company. For instance: @your-company.com. If not provided, the user entity profile email is used instead.
|
|
38
38
|
- `JIRA_ANNOTATION_PREFIX`: Optional annotation prefix for retrieving a custom annotation. Defaut value is jira.com. If you want to configure the plugin to be compatible with [Roadie's Backstage Jira Plugin](https://roadie.io/backstage/plugins/jira/), use the following annotation prefix:
|
|
39
39
|
|
|
40
40
|
```yaml
|
|
@@ -43,6 +43,57 @@ jiraDashboard:
|
|
|
43
43
|
annotationPrefix: jira
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
+
#### Authentication examples and trouble shooting
|
|
47
|
+
|
|
48
|
+
Either "Basic Auth" or "Personal Acccess Tokens" can be used.
|
|
49
|
+
|
|
50
|
+
This plugin will directly take the content of the "jiraDashboard.token" config string and
|
|
51
|
+
use as the "Authorization" header in all Jira REST API calls.
|
|
52
|
+
|
|
53
|
+
##### Basic Auth example
|
|
54
|
+
|
|
55
|
+
To use "Basic Auth" for authentication you need to create the "Authentication" header. See the [Jira documentation](https://developer.atlassian.com/cloud/jira/platform/basic-auth-for-rest-apis/#supply-basic-auth-headers) how to create and encode the token. This is the how to use the example token from the documentation (`ZnJlZDpmcmVk`) with `curl`.
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
curl -D- \
|
|
59
|
+
-X GET \
|
|
60
|
+
-H "Authorization: Basic ZnJlZDpmcmVk" \
|
|
61
|
+
-H "Content-Type: application/json" \
|
|
62
|
+
"https://your-domain.atlassian.net/rest/api/2/project/BS"
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
This would result in the following Backstage configuration:
|
|
66
|
+
|
|
67
|
+
```yaml
|
|
68
|
+
jiraDashboard:
|
|
69
|
+
token: Basic ZnJlZDpmcmVk
|
|
70
|
+
baseUrl: https://your-domain.atlassian.net/rest/api/2/
|
|
71
|
+
userEmailSuffix: ${JIRA_EMAIL_SUFFIX}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
##### Personal Acccess Tokens example
|
|
75
|
+
|
|
76
|
+
See the [Personal Acccess Tokens](https://confluence.atlassian.com/enterprise/using-personal-access-tokens-1026032365.html) documentation how to use and create
|
|
77
|
+
a PAT. The generated token can be directly used, there is no need to encode it. Using
|
|
78
|
+
`curl` with a PAT.
|
|
79
|
+
|
|
80
|
+
```sh
|
|
81
|
+
curl -D- \
|
|
82
|
+
-X GET \
|
|
83
|
+
-H "Authorization: Bearer <Token>" \
|
|
84
|
+
-H "Content-Type: application/json" \
|
|
85
|
+
"https://your-domain.atlassian.net/rest/api/2/project/BS"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
And the corresponding Backstage configuration:
|
|
89
|
+
|
|
90
|
+
```yaml
|
|
91
|
+
jiraDashboard:
|
|
92
|
+
token: Bearer <Token>
|
|
93
|
+
baseUrl: https://your-domain.atlassian.net/rest/api/2/
|
|
94
|
+
userEmailSuffix: ${JIRA_EMAIL_SUFFIX}
|
|
95
|
+
```
|
|
96
|
+
|
|
46
97
|
### Integrating
|
|
47
98
|
|
|
48
99
|
Here's how to get the backend plugin up and running:
|
package/config.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export interface Config {
|
|
|
13
13
|
baseUrl: string;
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
-
* Optional email suffix used for
|
|
16
|
+
* Optional email suffix used for retrieving a specific Jira user in a company. For instance: @your-company.com. If not provided, the user entity profile email is used instead.
|
|
17
17
|
*/
|
|
18
18
|
userEmailSuffix?: string;
|
|
19
19
|
|
package/dist/index.cjs.js
CHANGED
|
@@ -38,42 +38,64 @@ function resolveJiraToken(config) {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
function resolveUserEmailSuffix(config) {
|
|
41
|
-
return config.getOptionalString(JIRA_USER_CONFIG_EMAIL_SUFFIX)
|
|
41
|
+
return config.getOptionalString(JIRA_USER_CONFIG_EMAIL_SUFFIX);
|
|
42
42
|
}
|
|
43
43
|
function resolveAnnotationPrefix(config) {
|
|
44
44
|
const annotationPrefix = config.getOptionalString(JIRA_ANNOTATION);
|
|
45
45
|
return annotationPrefix != null ? annotationPrefix : "jira.com";
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
const getUsernameFromRef = (userRef) => {
|
|
49
|
-
return userRef == null ? void 0 : userRef.split("/").slice(1)[0];
|
|
50
|
-
};
|
|
51
48
|
const openFilter = {
|
|
52
49
|
name: "Open Issues",
|
|
53
50
|
shortName: "OPEN",
|
|
54
51
|
query: "resolution = Unresolved ORDER BY updated DESC"
|
|
55
52
|
};
|
|
56
|
-
const
|
|
53
|
+
const getIncomingFilter = (incomingStatus) => ({
|
|
57
54
|
name: "Incoming Issues",
|
|
58
55
|
shortName: "INCOMING",
|
|
59
|
-
query:
|
|
56
|
+
query: `status = ${incomingStatus} ORDER BY created ASC`
|
|
57
|
+
});
|
|
58
|
+
const getAssignedToMeFilter = (userEntity, config) => {
|
|
59
|
+
var _a, _b;
|
|
60
|
+
const emailSuffixConfig = resolveUserEmailSuffix(config);
|
|
61
|
+
const email = emailSuffixConfig ? `${userEntity.metadata.name}${emailSuffixConfig}` : (_b = (_a = userEntity.spec) == null ? void 0 : _a.profile) == null ? void 0 : _b.email;
|
|
62
|
+
return {
|
|
63
|
+
name: "Assigned to me",
|
|
64
|
+
shortName: "ME",
|
|
65
|
+
query: `assignee = "${email}" AND resolution = Unresolved ORDER BY updated DESC`
|
|
66
|
+
};
|
|
60
67
|
};
|
|
61
|
-
const
|
|
62
|
-
|
|
68
|
+
const getDefaultFiltersForUser = (config, userEntity, incomingStatus) => {
|
|
69
|
+
const incomingFilter = getIncomingFilter(incomingStatus != null ? incomingStatus : "New");
|
|
70
|
+
if (!userEntity)
|
|
63
71
|
return [openFilter, incomingFilter];
|
|
72
|
+
const assigneeToMeFilter = getAssignedToMeFilter(userEntity, config);
|
|
73
|
+
return [openFilter, incomingFilter, assigneeToMeFilter];
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const jqlQueryBuilder = ({
|
|
77
|
+
project,
|
|
78
|
+
components,
|
|
79
|
+
query
|
|
80
|
+
}) => {
|
|
81
|
+
let jql = `project in (${project})`;
|
|
82
|
+
if (components && components.length > 0) {
|
|
83
|
+
let componentsInclude = "(";
|
|
84
|
+
for (let index = 0; index < components.length; index++) {
|
|
85
|
+
const component = components[index];
|
|
86
|
+
componentsInclude += `'${component}'`;
|
|
87
|
+
if (index === components.length - 1) {
|
|
88
|
+
componentsInclude += ")";
|
|
89
|
+
} else {
|
|
90
|
+
componentsInclude += ",";
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
jql += ` AND component in ${componentsInclude}`;
|
|
64
94
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
return [openFilter, incomingFilter];
|
|
95
|
+
if (query) {
|
|
96
|
+
jql += ` AND ${query}`;
|
|
68
97
|
}
|
|
69
|
-
|
|
70
|
-
name: "Assigned to me",
|
|
71
|
-
shortName: "ME",
|
|
72
|
-
query: `assignee = "${username}${resolveUserEmailSuffix(
|
|
73
|
-
config
|
|
74
|
-
)}" AND resolution = Unresolved ORDER BY updated DESC`
|
|
75
|
-
};
|
|
76
|
-
return [openFilter, incomingFilter, assignedToMeFilter];
|
|
98
|
+
return jql;
|
|
77
99
|
};
|
|
78
100
|
|
|
79
101
|
const getProjectInfo = async (projectKey, config) => {
|
|
@@ -88,7 +110,9 @@ const getProjectInfo = async (projectKey, config) => {
|
|
|
88
110
|
}
|
|
89
111
|
);
|
|
90
112
|
if (response.status !== 200) {
|
|
91
|
-
throw Error(
|
|
113
|
+
throw Error(
|
|
114
|
+
`Request failed with status code ${response.status}: ${response.statusText}`
|
|
115
|
+
);
|
|
92
116
|
}
|
|
93
117
|
return response.json();
|
|
94
118
|
};
|
|
@@ -107,14 +131,9 @@ const getFilterById = async (id, config) => {
|
|
|
107
131
|
return { name: jsonResponse.name, query: jsonResponse.jql };
|
|
108
132
|
};
|
|
109
133
|
const getIssuesByFilter = async (projectKey, components, query, config) => {
|
|
110
|
-
|
|
111
|
-
if (components.length) {
|
|
112
|
-
componentQuery = `AND component in (${components})`;
|
|
113
|
-
}
|
|
134
|
+
const jql = jqlQueryBuilder({ project: projectKey, components, query });
|
|
114
135
|
const response = await fetch__default.default(
|
|
115
|
-
`${resolveJiraBaseUrl(
|
|
116
|
-
config
|
|
117
|
-
)}search?jql=project in (${projectKey}) ${componentQuery} AND ${query}`,
|
|
136
|
+
`${resolveJiraBaseUrl(config)}search?jql=${jql}`,
|
|
118
137
|
{
|
|
119
138
|
method: "GET",
|
|
120
139
|
headers: {
|
|
@@ -138,10 +157,12 @@ const searchJira = async (config, jqlQuery, options) => {
|
|
|
138
157
|
return response.issues;
|
|
139
158
|
};
|
|
140
159
|
const getIssuesByComponent = async (projectKey, componentKey, config) => {
|
|
160
|
+
const jql = jqlQueryBuilder({
|
|
161
|
+
project: projectKey,
|
|
162
|
+
components: [componentKey]
|
|
163
|
+
});
|
|
141
164
|
const response = await fetch__default.default(
|
|
142
|
-
`${resolveJiraBaseUrl(
|
|
143
|
-
config
|
|
144
|
-
)}search?jql=project=${projectKey} AND component = "${componentKey}"`,
|
|
165
|
+
`${resolveJiraBaseUrl(config)}search?jql=${jql}`,
|
|
145
166
|
{
|
|
146
167
|
method: "GET",
|
|
147
168
|
headers: {
|
|
@@ -172,7 +193,9 @@ const getProjectResponse = async (projectKey, config, cache) => {
|
|
|
172
193
|
cache.set(projectKey, projectResponse);
|
|
173
194
|
} catch (err) {
|
|
174
195
|
if (err.message !== 200) {
|
|
175
|
-
throw Error(
|
|
196
|
+
throw Error(
|
|
197
|
+
`Failed to get project info for project key ${projectKey} with error: ${err.message}`
|
|
198
|
+
);
|
|
176
199
|
}
|
|
177
200
|
}
|
|
178
201
|
return projectResponse;
|
|
@@ -220,12 +243,14 @@ const getAnnotations = (config) => {
|
|
|
220
243
|
const projectKeyAnnotation = `${prefix}/${pluginJiraDashboardCommon.PROJECT_KEY_NAME}`;
|
|
221
244
|
const componentsAnnotation = `${prefix}/${pluginJiraDashboardCommon.COMPONENTS_NAME}`;
|
|
222
245
|
const filtersAnnotation = `${prefix}/${pluginJiraDashboardCommon.FILTERS_NAME}`;
|
|
246
|
+
const incomingIssuesAnnotation = `${prefix}/${pluginJiraDashboardCommon.INCOMING_ISSUES_STATUS}`;
|
|
223
247
|
const componentRoadieAnnotation = `${prefix}/component`;
|
|
224
248
|
return {
|
|
225
249
|
projectKeyAnnotation,
|
|
226
250
|
componentsAnnotation,
|
|
227
|
-
|
|
228
|
-
|
|
251
|
+
filtersAnnotation,
|
|
252
|
+
incomingIssuesAnnotation,
|
|
253
|
+
componentRoadieAnnotation
|
|
229
254
|
};
|
|
230
255
|
};
|
|
231
256
|
|
|
@@ -245,7 +270,7 @@ async function createRouter(options) {
|
|
|
245
270
|
router.get(
|
|
246
271
|
"/dashboards/by-entity-ref/:kind/:namespace/:name",
|
|
247
272
|
async (request, response) => {
|
|
248
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
273
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
|
|
249
274
|
const { kind, namespace, name } = request.params;
|
|
250
275
|
const entityRef = catalogModel.stringifyEntityRef({ kind, namespace, name });
|
|
251
276
|
const { token } = await auth.getPluginRequestToken({
|
|
@@ -256,8 +281,9 @@ async function createRouter(options) {
|
|
|
256
281
|
const {
|
|
257
282
|
projectKeyAnnotation,
|
|
258
283
|
componentsAnnotation,
|
|
259
|
-
|
|
260
|
-
|
|
284
|
+
filtersAnnotation,
|
|
285
|
+
incomingIssuesAnnotation,
|
|
286
|
+
componentRoadieAnnotation
|
|
261
287
|
} = getAnnotations(config);
|
|
262
288
|
if (!entity) {
|
|
263
289
|
logger.info(`No entity found for ${entityRef}`);
|
|
@@ -279,28 +305,36 @@ async function createRouter(options) {
|
|
|
279
305
|
cache
|
|
280
306
|
);
|
|
281
307
|
} catch (err) {
|
|
282
|
-
logger.error(
|
|
308
|
+
logger.error(
|
|
309
|
+
`Could not find Jira project ${projectKey[0]}: ${err.message}`
|
|
310
|
+
);
|
|
283
311
|
response.status(404).json({
|
|
284
312
|
error: `No Jira project found with key ${projectKey[0]}`
|
|
285
313
|
});
|
|
286
314
|
return;
|
|
287
315
|
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
316
|
+
let userEntity;
|
|
317
|
+
try {
|
|
318
|
+
const credentials = await httpAuth.credentials(request, {
|
|
319
|
+
allow: ["user"]
|
|
320
|
+
});
|
|
321
|
+
const userIdentity = credentials.principal.userEntityRef;
|
|
322
|
+
userEntity = await catalogClient$1.getEntityByRef(userIdentity, {
|
|
323
|
+
token
|
|
324
|
+
});
|
|
325
|
+
} catch (err) {
|
|
326
|
+
logger.warn("Could not find user identity");
|
|
294
327
|
}
|
|
295
328
|
let filters = [];
|
|
296
|
-
const
|
|
297
|
-
filters =
|
|
329
|
+
const incomingStatus = (_c = entity.metadata.annotations) == null ? void 0 : _c[incomingIssuesAnnotation];
|
|
330
|
+
filters = getDefaultFiltersForUser(config, userEntity, incomingStatus);
|
|
331
|
+
const customFilterAnnotations = (_e = (_d = entity.metadata.annotations) == null ? void 0 : _d[filtersAnnotation]) == null ? void 0 : _e.split(",");
|
|
298
332
|
if (customFilterAnnotations) {
|
|
299
333
|
filters.push(
|
|
300
334
|
...await getFiltersFromAnnotations(customFilterAnnotations, config)
|
|
301
335
|
);
|
|
302
336
|
}
|
|
303
|
-
let components = (
|
|
337
|
+
let components = (_h = (_g = (_f = entity.metadata.annotations) == null ? void 0 : _f[componentsAnnotation]) == null ? void 0 : _g.split(",")) != null ? _h : [];
|
|
304
338
|
let issues = await getIssuesFromFilters(
|
|
305
339
|
projectKey[0],
|
|
306
340
|
components,
|
|
@@ -308,7 +342,7 @@ async function createRouter(options) {
|
|
|
308
342
|
config
|
|
309
343
|
);
|
|
310
344
|
components = components.concat(
|
|
311
|
-
(
|
|
345
|
+
(_k = (_j = (_i = entity.metadata.annotations) == null ? void 0 : _i[componentRoadieAnnotation]) == null ? void 0 : _j.split(",")) != null ? _k : []
|
|
312
346
|
);
|
|
313
347
|
if (components) {
|
|
314
348
|
const componentIssues = await getIssuesFromComponents(
|
|
@@ -403,5 +437,6 @@ const jiraDashboardPlugin = backendPluginApi.createBackendPlugin({
|
|
|
403
437
|
|
|
404
438
|
exports.createRouter = createRouter;
|
|
405
439
|
exports.default = jiraDashboardPlugin;
|
|
440
|
+
exports.jqlQueryBuilder = jqlQueryBuilder;
|
|
406
441
|
exports.searchJira = searchJira;
|
|
407
442
|
//# sourceMappingURL=index.cjs.js.map
|
package/dist/index.cjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs.js","sources":["../src/config.ts","../src/filters.ts","../src/api.ts","../src/service/service.ts","../src/lib.ts","../src/service/router.ts","../src/plugin.ts"],"sourcesContent":["import { Config } from '@backstage/config';\n\nconst JIRA_BASE_URL_CONFIG_PATH = 'jiraDashboard.baseUrl';\nconst JIRA_TOKEN_CONFIG_PATH = 'jiraDashboard.token';\nconst JIRA_USER_CONFIG_EMAIL_SUFFIX = 'jiraDashboard.userEmailSuffix';\nconst JIRA_ANNOTATION = 'jiraDashboard.annotationPrefix';\n\nexport function resolveJiraBaseUrl(config: Config): string {\n try {\n return config.getString(JIRA_BASE_URL_CONFIG_PATH);\n } catch (error) {\n throw new Error(`Invalid Jira baseUrl, ${error}`);\n }\n}\n\nexport function resolveJiraToken(config: Config): string {\n try {\n return config.getString(JIRA_TOKEN_CONFIG_PATH);\n } catch (error) {\n throw new Error(`Invalid Jira token, ${error}`);\n }\n}\n\nexport function resolveUserEmailSuffix(config: Config): string {\n return config.getOptionalString(JIRA_USER_CONFIG_EMAIL_SUFFIX) || '';\n}\n\nexport function resolveAnnotationPrefix(config: Config): string {\n const annotationPrefix = config.getOptionalString(JIRA_ANNOTATION);\n return annotationPrefix ?? 'jira.com';\n}\n","import { Config } from '@backstage/config';\nimport { resolveUserEmailSuffix } from './config';\nimport { Filter } from '@axis-backstage/plugin-jira-dashboard-common';\n\nconst getUsernameFromRef = (userRef: string) => {\n return userRef?.split('/').slice(1)[0];\n};\n\nconst openFilter: Filter = {\n name: 'Open Issues',\n shortName: 'OPEN',\n query: 'resolution = Unresolved ORDER BY updated DESC',\n};\n\nconst incomingFilter: Filter = {\n name: 'Incoming Issues',\n shortName: 'INCOMING',\n query: 'status = New ORDER BY created ASC',\n};\n\nexport const getDefaultFilters = (\n config: Config,\n userRef?: string,\n): Filter[] => {\n if (!userRef) {\n return [openFilter, incomingFilter];\n }\n const username = getUsernameFromRef(userRef);\n\n if (!username) {\n return [openFilter, incomingFilter];\n }\n\n const assignedToMeFilter: Filter = {\n name: 'Assigned to me',\n shortName: 'ME',\n query: `assignee = \"${username}${resolveUserEmailSuffix(\n config,\n )}\" AND resolution = Unresolved ORDER BY updated DESC`,\n };\n\n return [openFilter, incomingFilter, assignedToMeFilter];\n};\n","import { Config } from '@backstage/config';\nimport fetch from 'node-fetch';\nimport {\n Filter,\n Issue,\n Project,\n} from '@axis-backstage/plugin-jira-dashboard-common';\nimport { resolveJiraBaseUrl, resolveJiraToken } from './config';\n\nexport const getProjectInfo = async (\n projectKey: string,\n config: Config,\n): Promise<Project> => {\n const response = await fetch(\n `${resolveJiraBaseUrl(config)}project/${projectKey}`,\n {\n method: 'GET',\n headers: {\n Authorization: resolveJiraToken(config),\n Accept: 'application/json',\n },\n },\n );\n if (response.status !== 200) {\n throw Error(`${response.status}`);\n }\n return response.json();\n};\n\nexport const getFilterById = async (\n id: string,\n config: Config,\n): Promise<Filter> => {\n const response = await fetch(`${resolveJiraBaseUrl(config)}filter/${id}`, {\n method: 'GET',\n headers: {\n Authorization: resolveJiraToken(config),\n Accept: 'application/json',\n },\n });\n if (response.status !== 200) {\n throw Error(`${response.status}`);\n }\n const jsonResponse = await response.json();\n return { name: jsonResponse.name, query: jsonResponse.jql } as Filter;\n};\n\nexport const getIssuesByFilter = async (\n projectKey: string,\n components: string[],\n query: string,\n config: Config,\n): Promise<Issue[]> => {\n let componentQuery = '';\n if (components.length) {\n componentQuery = `AND component in (${components})`;\n }\n const response = await fetch(\n `${resolveJiraBaseUrl(\n config,\n )}search?jql=project in (${projectKey}) ${componentQuery} AND ${query}`,\n {\n method: 'GET',\n headers: {\n Authorization: resolveJiraToken(config),\n Accept: 'application/json',\n },\n },\n ).then(resp => resp.json());\n return response.issues;\n};\n\n/**\n * Options available for the Jira JQL query.\n *\n * @public\n */\nexport type SearchOptions = {\n expand?: string[];\n fields?: string[];\n fieldsByKey?: boolean;\n properties?: string[];\n startAt?: number;\n maxResults?: number;\n validateQuery?: string;\n};\n\n/**\n * Search for Jira issues using JQL.\n *\n * For more information about the available options see the API\n * documentation at:\n * https://developer.atlassian.com/cloud/jira/platform/rest/v2/api-group-issue-search/#api-rest-api-2-search-post\n *\n * @param config - A Backstage config\n * @param jqlQuery - A string containing the jql query.\n * @param options - Query options that will be passed on to the POST request.\n *\n * @public\n */\nexport const searchJira = async (\n config: Config,\n jqlQuery: string,\n options: SearchOptions,\n): Promise<Issue[]> => {\n const response = await fetch(`${resolveJiraBaseUrl(config)}search`, {\n method: 'POST',\n body: JSON.stringify({ jql: jqlQuery, ...options }),\n headers: {\n Authorization: resolveJiraToken(config),\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n },\n }).then(resp => resp.json());\n return response.issues;\n};\n\nexport const getIssuesByComponent = async (\n projectKey: string,\n componentKey: string,\n config: Config,\n): Promise<Issue[]> => {\n const response = await fetch(\n `${resolveJiraBaseUrl(\n config,\n )}search?jql=project=${projectKey} AND component = \"${componentKey}\"`,\n {\n method: 'GET',\n headers: {\n Authorization: resolveJiraToken(config),\n Accept: 'application/json',\n },\n },\n ).then(resp => resp.json());\n return response.issues;\n};\n\nexport async function getProjectAvatar(url: string, config: Config) {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n Authorization: resolveJiraToken(config),\n },\n });\n return response;\n}\n","import { CacheClient } from '@backstage/backend-common';\nimport { Config } from '@backstage/config';\nimport {\n type Filter,\n type JiraDataResponse,\n type Project,\n} from '@axis-backstage/plugin-jira-dashboard-common';\nimport {\n getFilterById,\n getIssuesByComponent,\n getIssuesByFilter,\n getProjectInfo,\n} from '../api';\n\nexport const getProjectResponse = async (\n projectKey: string,\n config: Config,\n cache: CacheClient,\n): Promise<Project> => {\n let projectResponse: Project;\n\n projectResponse = (await cache.get(projectKey)) as Project;\n\n if (projectResponse) return projectResponse as Project;\n\n try {\n projectResponse = await getProjectInfo(projectKey, config);\n cache.set(projectKey, projectResponse);\n } catch (err: any) {\n if (err.message !== 200) {\n throw Error(`${err.status}`);\n }\n }\n return projectResponse;\n};\n\nexport const getFiltersFromAnnotations = async (\n annotations: string[],\n config: Config,\n): Promise<Filter[]> => {\n const filters: Filter[] = [];\n\n for (const filter of annotations) {\n try {\n const response = await getFilterById(filter, config);\n filters.push(response);\n } catch (err: any) {\n console.warn(\n `${err.message} : Could not find filter with filter id ${filter}`,\n );\n }\n }\n return filters;\n};\n\nexport const getIssuesFromFilters = async (\n projectKey: string,\n components: string[],\n filters: Filter[],\n config: Config,\n): Promise<JiraDataResponse[]> => {\n return await Promise.all(\n filters.map(async filter => ({\n name: filter.name,\n type: 'filter',\n issues: await getIssuesByFilter(\n projectKey,\n components,\n filter.query,\n config,\n ),\n })),\n );\n};\n\nexport const getIssuesFromComponents = async (\n projectKey: string,\n componentAnnotations: string[],\n config: Config,\n): Promise<JiraDataResponse[]> => {\n return await Promise.all(\n componentAnnotations.map(async componentKey => ({\n name: componentKey,\n type: 'component',\n issues: await getIssuesByComponent(projectKey, componentKey, config),\n })),\n );\n};\n","import { resolveAnnotationPrefix } from './config';\nimport {\n COMPONENTS_NAME,\n PROJECT_KEY_NAME,\n FILTERS_NAME,\n} from '@axis-backstage/plugin-jira-dashboard-common';\nimport { Config } from '@backstage/config';\n\nexport const getAnnotations = (config: Config) => {\n const prefix = resolveAnnotationPrefix(config);\n\n const projectKeyAnnotation = `${prefix}/${PROJECT_KEY_NAME}`;\n const componentsAnnotation = `${prefix}/${COMPONENTS_NAME}`;\n const filtersAnnotation = `${prefix}/${FILTERS_NAME}`;\n\n /* Adding support for Roadie's component annotation */\n const componentRoadieAnnotation = `${prefix}/component`;\n\n return {\n projectKeyAnnotation,\n componentsAnnotation,\n componentRoadieAnnotation,\n filtersAnnotation,\n };\n};\n","import {\n CacheManager,\n TokenManager,\n createLegacyAuthAdapters,\n errorHandler,\n} from '@backstage/backend-common';\nimport {\n AuthService,\n DiscoveryService,\n HttpAuthService,\n} from '@backstage/backend-plugin-api';\nimport { stringifyEntityRef } from '@backstage/catalog-model';\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { Config } from '@backstage/config';\nimport { Logger } from 'winston';\nimport { CatalogClient } from '@backstage/catalog-client';\nimport { IdentityApi } from '@backstage/plugin-auth-node';\n\nimport { getDefaultFilters } from '../filters';\nimport {\n type Filter,\n type JiraResponse,\n type Project,\n} from '@axis-backstage/plugin-jira-dashboard-common';\nimport stream from 'stream';\nimport { getProjectAvatar } from '../api';\nimport {\n getProjectResponse,\n getFiltersFromAnnotations,\n getIssuesFromFilters,\n getIssuesFromComponents,\n} from './service';\nimport { getAnnotations } from '../lib';\n\n/**\n * Constructs a jira dashboard router.\n * @public\n */\nexport interface RouterOptions {\n /**\n * Implementation of Winston logger\n */\n logger: Logger;\n\n /**\n * Backstage config object\n */\n config: Config;\n\n /**\n * Backstage discovery api instance\n */\n discovery: DiscoveryService;\n\n /**\n * Backstage identity api instance\n */\n identity?: IdentityApi;\n\n /**\n * Backstage token manager instance\n */\n tokenManager?: TokenManager;\n /**\n * Backstage auth service\n */\n auth?: AuthService;\n /**\n * Backstage httpAuth service\n */\n httpAuth?: HttpAuthService;\n}\n\nconst DEFAULT_TTL = 1000 * 60;\n\n/**\n * Constructs a jira dashboard router.\n *\n * @public\n */\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const { auth, httpAuth } = createLegacyAuthAdapters(options);\n const { logger, config, discovery } = options;\n const catalogClient = new CatalogClient({ discoveryApi: discovery });\n logger.info('Initializing Jira Dashboard backend');\n\n const pluginCache =\n CacheManager.fromConfig(config).forPlugin('jira-dashboard');\n const cache = pluginCache.getClient({ defaultTtl: DEFAULT_TTL });\n\n const router = Router();\n router.use(express.json());\n\n router.get('/health', (_, response) => {\n response.json({ status: 'ok' });\n });\n\n router.get(\n '/dashboards/by-entity-ref/:kind/:namespace/:name',\n async (request, response) => {\n const { kind, namespace, name } = request.params;\n const entityRef = stringifyEntityRef({ kind, namespace, name });\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n const entity = await catalogClient.getEntityByRef(entityRef, { token });\n const {\n projectKeyAnnotation,\n componentsAnnotation,\n componentRoadieAnnotation,\n filtersAnnotation,\n } = getAnnotations(config);\n\n if (!entity) {\n logger.info(`No entity found for ${entityRef}`);\n response\n .status(500)\n .json({ error: `No entity found for ${entityRef}` });\n return;\n }\n\n const projectKey =\n entity.metadata.annotations?.[projectKeyAnnotation]?.split(',')!;\n\n if (!projectKey) {\n const error = `No jira.com/project-key annotation found for ${entityRef}`;\n logger.info(error);\n response.status(404).json(error);\n return;\n }\n\n let projectResponse;\n\n try {\n projectResponse = await getProjectResponse(\n projectKey[0],\n config,\n cache,\n );\n } catch (err) {\n logger.error(`Could not find Jira project ${projectKey[0]}`);\n response.status(404).json({\n error: `No Jira project found with key ${projectKey[0]}`,\n });\n return;\n }\n\n const credentials = await httpAuth.credentials(request, {\n allow: ['user'],\n });\n\n const userEntityRef = credentials.principal.userEntityRef;\n\n if (!userEntityRef) {\n logger.warn(`Could not find user identity`);\n }\n\n let filters: Filter[] = [];\n\n const customFilterAnnotations =\n entity.metadata.annotations?.[filtersAnnotation]?.split(',')!;\n\n filters = getDefaultFilters(config, userEntityRef);\n\n if (customFilterAnnotations) {\n filters.push(\n ...(await getFiltersFromAnnotations(customFilterAnnotations, config)),\n );\n }\n\n let components =\n entity.metadata.annotations?.[componentsAnnotation]?.split(',') ?? [];\n let issues = await getIssuesFromFilters(\n projectKey[0],\n components,\n filters,\n config,\n );\n\n /* Adding support for Roadie's component annotation */\n components = components.concat(\n entity.metadata.annotations?.[componentRoadieAnnotation]?.split(',') ??\n [],\n );\n\n if (components) {\n const componentIssues = await getIssuesFromComponents(\n projectKey[0],\n components,\n config,\n );\n issues = issues.concat(componentIssues);\n }\n\n const jiraResponse: JiraResponse = {\n project: projectResponse as Project,\n data: issues,\n };\n response.json(jiraResponse);\n },\n );\n\n router.get(\n '/avatar/by-entity-ref/:kind/:namespace/:name',\n async (request, response) => {\n const { kind, namespace, name } = request.params;\n const entityRef = stringifyEntityRef({ kind, namespace, name });\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n const entity = await catalogClient.getEntityByRef(entityRef, { token });\n const { projectKeyAnnotation } = getAnnotations(config);\n\n if (!entity) {\n logger.info(`No entity found for ${entityRef}`);\n response\n .status(500)\n .json({ error: `No entity found for ${entityRef}` });\n return;\n }\n\n const projectKey =\n entity.metadata.annotations?.[projectKeyAnnotation]?.split(',')!;\n\n const projectResponse = await getProjectResponse(\n projectKey[0],\n config,\n cache,\n );\n\n if (!projectResponse) {\n logger.error('Could not find project in Jira');\n response.status(400).json({\n error: `No Jira project found for project key ${projectKey[0]}`,\n });\n return;\n }\n\n const url = projectResponse.avatarUrls['48x48'];\n\n const avatar = await getProjectAvatar(url, config);\n\n const ps = new stream.PassThrough();\n const val = avatar.headers.get('content-type');\n\n response.setHeader('content-type', val ?? '');\n stream.pipeline(avatar.body, ps, err => {\n if (err) {\n logger.error(err);\n response.sendStatus(400);\n }\n return;\n });\n ps.pipe(response);\n },\n );\n router.use(errorHandler());\n return router;\n}\n","import { loggerToWinstonLogger } from '@backstage/backend-common';\nimport {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { createRouter } from './service/router';\n\n/**\n * The Jira Dashboard backend plugin.\n *\n * @public\n */\nexport const jiraDashboardPlugin = createBackendPlugin({\n pluginId: 'jira-dashboard',\n register(env) {\n env.registerInit({\n deps: {\n logger: coreServices.logger,\n config: coreServices.rootConfig,\n discovery: coreServices.discovery,\n httpRouter: coreServices.httpRouter,\n auth: coreServices.auth,\n httpAuth: coreServices.httpAuth,\n },\n async init({ logger, config, discovery, httpRouter, auth, httpAuth }) {\n httpRouter.use(\n await createRouter({\n logger: loggerToWinstonLogger(logger),\n config,\n discovery,\n auth,\n httpAuth,\n }),\n );\n },\n });\n },\n});\n"],"names":["fetch","PROJECT_KEY_NAME","COMPONENTS_NAME","FILTERS_NAME","createLegacyAuthAdapters","catalogClient","CatalogClient","CacheManager","Router","express","stringifyEntityRef","stream","errorHandler","createBackendPlugin","coreServices","loggerToWinstonLogger"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAEA,MAAM,yBAA4B,GAAA,uBAAA,CAAA;AAClC,MAAM,sBAAyB,GAAA,qBAAA,CAAA;AAC/B,MAAM,6BAAgC,GAAA,+BAAA,CAAA;AACtC,MAAM,eAAkB,GAAA,gCAAA,CAAA;AAEjB,SAAS,mBAAmB,MAAwB,EAAA;AACzD,EAAI,IAAA;AACF,IAAO,OAAA,MAAA,CAAO,UAAU,yBAAyB,CAAA,CAAA;AAAA,WAC1C,KAAO,EAAA;AACd,IAAA,MAAM,IAAI,KAAA,CAAM,CAAyB,sBAAA,EAAA,KAAK,CAAE,CAAA,CAAA,CAAA;AAAA,GAClD;AACF,CAAA;AAEO,SAAS,iBAAiB,MAAwB,EAAA;AACvD,EAAI,IAAA;AACF,IAAO,OAAA,MAAA,CAAO,UAAU,sBAAsB,CAAA,CAAA;AAAA,WACvC,KAAO,EAAA;AACd,IAAA,MAAM,IAAI,KAAA,CAAM,CAAuB,oBAAA,EAAA,KAAK,CAAE,CAAA,CAAA,CAAA;AAAA,GAChD;AACF,CAAA;AAEO,SAAS,uBAAuB,MAAwB,EAAA;AAC7D,EAAO,OAAA,MAAA,CAAO,iBAAkB,CAAA,6BAA6B,CAAK,IAAA,EAAA,CAAA;AACpE,CAAA;AAEO,SAAS,wBAAwB,MAAwB,EAAA;AAC9D,EAAM,MAAA,gBAAA,GAAmB,MAAO,CAAA,iBAAA,CAAkB,eAAe,CAAA,CAAA;AACjE,EAAA,OAAO,gBAAoB,IAAA,IAAA,GAAA,gBAAA,GAAA,UAAA,CAAA;AAC7B;;AC1BA,MAAM,kBAAA,GAAqB,CAAC,OAAoB,KAAA;AAC9C,EAAA,OAAO,OAAS,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,OAAA,CAAA,KAAA,CAAM,GAAK,CAAA,CAAA,KAAA,CAAM,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA;AACtC,CAAA,CAAA;AAEA,MAAM,UAAqB,GAAA;AAAA,EACzB,IAAM,EAAA,aAAA;AAAA,EACN,SAAW,EAAA,MAAA;AAAA,EACX,KAAO,EAAA,+CAAA;AACT,CAAA,CAAA;AAEA,MAAM,cAAyB,GAAA;AAAA,EAC7B,IAAM,EAAA,iBAAA;AAAA,EACN,SAAW,EAAA,UAAA;AAAA,EACX,KAAO,EAAA,mCAAA;AACT,CAAA,CAAA;AAEa,MAAA,iBAAA,GAAoB,CAC/B,MAAA,EACA,OACa,KAAA;AACb,EAAA,IAAI,CAAC,OAAS,EAAA;AACZ,IAAO,OAAA,CAAC,YAAY,cAAc,CAAA,CAAA;AAAA,GACpC;AACA,EAAM,MAAA,QAAA,GAAW,mBAAmB,OAAO,CAAA,CAAA;AAE3C,EAAA,IAAI,CAAC,QAAU,EAAA;AACb,IAAO,OAAA,CAAC,YAAY,cAAc,CAAA,CAAA;AAAA,GACpC;AAEA,EAAA,MAAM,kBAA6B,GAAA;AAAA,IACjC,IAAM,EAAA,gBAAA;AAAA,IACN,SAAW,EAAA,IAAA;AAAA,IACX,KAAA,EAAO,CAAe,YAAA,EAAA,QAAQ,CAAG,EAAA,sBAAA;AAAA,MAC/B,MAAA;AAAA,KACD,CAAA,mDAAA,CAAA;AAAA,GACH,CAAA;AAEA,EAAO,OAAA,CAAC,UAAY,EAAA,cAAA,EAAgB,kBAAkB,CAAA,CAAA;AACxD,CAAA;;ACjCa,MAAA,cAAA,GAAiB,OAC5B,UAAA,EACA,MACqB,KAAA;AACrB,EAAA,MAAM,WAAW,MAAMA,sBAAA;AAAA,IACrB,CAAG,EAAA,kBAAA,CAAmB,MAAM,CAAC,WAAW,UAAU,CAAA,CAAA;AAAA,IAClD;AAAA,MACE,MAAQ,EAAA,KAAA;AAAA,MACR,OAAS,EAAA;AAAA,QACP,aAAA,EAAe,iBAAiB,MAAM,CAAA;AAAA,QACtC,MAAQ,EAAA,kBAAA;AAAA,OACV;AAAA,KACF;AAAA,GACF,CAAA;AACA,EAAI,IAAA,QAAA,CAAS,WAAW,GAAK,EAAA;AAC3B,IAAA,MAAM,KAAM,CAAA,CAAA,EAAG,QAAS,CAAA,MAAM,CAAE,CAAA,CAAA,CAAA;AAAA,GAClC;AACA,EAAA,OAAO,SAAS,IAAK,EAAA,CAAA;AACvB,CAAA,CAAA;AAEa,MAAA,aAAA,GAAgB,OAC3B,EAAA,EACA,MACoB,KAAA;AACpB,EAAM,MAAA,QAAA,GAAW,MAAMA,sBAAM,CAAA,CAAA,EAAG,mBAAmB,MAAM,CAAC,CAAU,OAAA,EAAA,EAAE,CAAI,CAAA,EAAA;AAAA,IACxE,MAAQ,EAAA,KAAA;AAAA,IACR,OAAS,EAAA;AAAA,MACP,aAAA,EAAe,iBAAiB,MAAM,CAAA;AAAA,MACtC,MAAQ,EAAA,kBAAA;AAAA,KACV;AAAA,GACD,CAAA,CAAA;AACD,EAAI,IAAA,QAAA,CAAS,WAAW,GAAK,EAAA;AAC3B,IAAA,MAAM,KAAM,CAAA,CAAA,EAAG,QAAS,CAAA,MAAM,CAAE,CAAA,CAAA,CAAA;AAAA,GAClC;AACA,EAAM,MAAA,YAAA,GAAe,MAAM,QAAA,CAAS,IAAK,EAAA,CAAA;AACzC,EAAA,OAAO,EAAE,IAAM,EAAA,YAAA,CAAa,IAAM,EAAA,KAAA,EAAO,aAAa,GAAI,EAAA,CAAA;AAC5D,CAAA,CAAA;AAEO,MAAM,iBAAoB,GAAA,OAC/B,UACA,EAAA,UAAA,EACA,OACA,MACqB,KAAA;AACrB,EAAA,IAAI,cAAiB,GAAA,EAAA,CAAA;AACrB,EAAA,IAAI,WAAW,MAAQ,EAAA;AACrB,IAAA,cAAA,GAAiB,qBAAqB,UAAU,CAAA,CAAA,CAAA,CAAA;AAAA,GAClD;AACA,EAAA,MAAM,WAAW,MAAMA,sBAAA;AAAA,IACrB,CAAG,EAAA,kBAAA;AAAA,MACD,MAAA;AAAA,KACD,CAA0B,uBAAA,EAAA,UAAU,CAAK,EAAA,EAAA,cAAc,QAAQ,KAAK,CAAA,CAAA;AAAA,IACrE;AAAA,MACE,MAAQ,EAAA,KAAA;AAAA,MACR,OAAS,EAAA;AAAA,QACP,aAAA,EAAe,iBAAiB,MAAM,CAAA;AAAA,QACtC,MAAQ,EAAA,kBAAA;AAAA,OACV;AAAA,KACF;AAAA,GACA,CAAA,IAAA,CAAK,CAAQ,IAAA,KAAA,IAAA,CAAK,MAAM,CAAA,CAAA;AAC1B,EAAA,OAAO,QAAS,CAAA,MAAA,CAAA;AAClB,CAAA,CAAA;AA8BO,MAAM,UAAa,GAAA,OACxB,MACA,EAAA,QAAA,EACA,OACqB,KAAA;AACrB,EAAA,MAAM,WAAW,MAAMA,sBAAA,CAAM,GAAG,kBAAmB,CAAA,MAAM,CAAC,CAAU,MAAA,CAAA,EAAA;AAAA,IAClE,MAAQ,EAAA,MAAA;AAAA,IACR,IAAA,EAAM,KAAK,SAAU,CAAA,EAAE,KAAK,QAAU,EAAA,GAAG,SAAS,CAAA;AAAA,IAClD,OAAS,EAAA;AAAA,MACP,aAAA,EAAe,iBAAiB,MAAM,CAAA;AAAA,MACtC,MAAQ,EAAA,kBAAA;AAAA,MACR,cAAgB,EAAA,kBAAA;AAAA,KAClB;AAAA,GACD,CAAE,CAAA,IAAA,CAAK,CAAQ,IAAA,KAAA,IAAA,CAAK,MAAM,CAAA,CAAA;AAC3B,EAAA,OAAO,QAAS,CAAA,MAAA,CAAA;AAClB,EAAA;AAEO,MAAM,oBAAuB,GAAA,OAClC,UACA,EAAA,YAAA,EACA,MACqB,KAAA;AACrB,EAAA,MAAM,WAAW,MAAMA,sBAAA;AAAA,IACrB,CAAG,EAAA,kBAAA;AAAA,MACD,MAAA;AAAA,KACD,CAAA,mBAAA,EAAsB,UAAU,CAAA,kBAAA,EAAqB,YAAY,CAAA,CAAA,CAAA;AAAA,IAClE;AAAA,MACE,MAAQ,EAAA,KAAA;AAAA,MACR,OAAS,EAAA;AAAA,QACP,aAAA,EAAe,iBAAiB,MAAM,CAAA;AAAA,QACtC,MAAQ,EAAA,kBAAA;AAAA,OACV;AAAA,KACF;AAAA,GACA,CAAA,IAAA,CAAK,CAAQ,IAAA,KAAA,IAAA,CAAK,MAAM,CAAA,CAAA;AAC1B,EAAA,OAAO,QAAS,CAAA,MAAA,CAAA;AAClB,CAAA,CAAA;AAEsB,eAAA,gBAAA,CAAiB,KAAa,MAAgB,EAAA;AAClE,EAAM,MAAA,QAAA,GAAW,MAAMA,sBAAA,CAAM,GAAK,EAAA;AAAA,IAChC,MAAQ,EAAA,KAAA;AAAA,IACR,OAAS,EAAA;AAAA,MACP,aAAA,EAAe,iBAAiB,MAAM,CAAA;AAAA,KACxC;AAAA,GACD,CAAA,CAAA;AACD,EAAO,OAAA,QAAA,CAAA;AACT;;ACnIO,MAAM,kBAAqB,GAAA,OAChC,UACA,EAAA,MAAA,EACA,KACqB,KAAA;AACrB,EAAI,IAAA,eAAA,CAAA;AAEJ,EAAmB,eAAA,GAAA,MAAM,KAAM,CAAA,GAAA,CAAI,UAAU,CAAA,CAAA;AAE7C,EAAI,IAAA,eAAA;AAAiB,IAAO,OAAA,eAAA,CAAA;AAE5B,EAAI,IAAA;AACF,IAAkB,eAAA,GAAA,MAAM,cAAe,CAAA,UAAA,EAAY,MAAM,CAAA,CAAA;AACzD,IAAM,KAAA,CAAA,GAAA,CAAI,YAAY,eAAe,CAAA,CAAA;AAAA,WAC9B,GAAU,EAAA;AACjB,IAAI,IAAA,GAAA,CAAI,YAAY,GAAK,EAAA;AACvB,MAAA,MAAM,KAAM,CAAA,CAAA,EAAG,GAAI,CAAA,MAAM,CAAE,CAAA,CAAA,CAAA;AAAA,KAC7B;AAAA,GACF;AACA,EAAO,OAAA,eAAA,CAAA;AACT,CAAA,CAAA;AAEa,MAAA,yBAAA,GAA4B,OACvC,WAAA,EACA,MACsB,KAAA;AACtB,EAAA,MAAM,UAAoB,EAAC,CAAA;AAE3B,EAAA,KAAA,MAAW,UAAU,WAAa,EAAA;AAChC,IAAI,IAAA;AACF,MAAA,MAAM,QAAW,GAAA,MAAM,aAAc,CAAA,MAAA,EAAQ,MAAM,CAAA,CAAA;AACnD,MAAA,OAAA,CAAQ,KAAK,QAAQ,CAAA,CAAA;AAAA,aACd,GAAU,EAAA;AACjB,MAAQ,OAAA,CAAA,IAAA;AAAA,QACN,CAAG,EAAA,GAAA,CAAI,OAAO,CAAA,wCAAA,EAA2C,MAAM,CAAA,CAAA;AAAA,OACjE,CAAA;AAAA,KACF;AAAA,GACF;AACA,EAAO,OAAA,OAAA,CAAA;AACT,CAAA,CAAA;AAEO,MAAM,oBAAuB,GAAA,OAClC,UACA,EAAA,UAAA,EACA,SACA,MACgC,KAAA;AAChC,EAAA,OAAO,MAAM,OAAQ,CAAA,GAAA;AAAA,IACnB,OAAA,CAAQ,GAAI,CAAA,OAAM,MAAW,MAAA;AAAA,MAC3B,MAAM,MAAO,CAAA,IAAA;AAAA,MACb,IAAM,EAAA,QAAA;AAAA,MACN,QAAQ,MAAM,iBAAA;AAAA,QACZ,UAAA;AAAA,QACA,UAAA;AAAA,QACA,MAAO,CAAA,KAAA;AAAA,QACP,MAAA;AAAA,OACF;AAAA,KACA,CAAA,CAAA;AAAA,GACJ,CAAA;AACF,CAAA,CAAA;AAEO,MAAM,uBAA0B,GAAA,OACrC,UACA,EAAA,oBAAA,EACA,MACgC,KAAA;AAChC,EAAA,OAAO,MAAM,OAAQ,CAAA,GAAA;AAAA,IACnB,oBAAA,CAAqB,GAAI,CAAA,OAAM,YAAiB,MAAA;AAAA,MAC9C,IAAM,EAAA,YAAA;AAAA,MACN,IAAM,EAAA,WAAA;AAAA,MACN,MAAQ,EAAA,MAAM,oBAAqB,CAAA,UAAA,EAAY,cAAc,MAAM,CAAA;AAAA,KACnE,CAAA,CAAA;AAAA,GACJ,CAAA;AACF,CAAA;;AC/Ea,MAAA,cAAA,GAAiB,CAAC,MAAmB,KAAA;AAChD,EAAM,MAAA,MAAA,GAAS,wBAAwB,MAAM,CAAA,CAAA;AAE7C,EAAA,MAAM,oBAAuB,GAAA,CAAA,EAAG,MAAM,CAAA,CAAA,EAAIC,0CAAgB,CAAA,CAAA,CAAA;AAC1D,EAAA,MAAM,oBAAuB,GAAA,CAAA,EAAG,MAAM,CAAA,CAAA,EAAIC,yCAAe,CAAA,CAAA,CAAA;AACzD,EAAA,MAAM,iBAAoB,GAAA,CAAA,EAAG,MAAM,CAAA,CAAA,EAAIC,sCAAY,CAAA,CAAA,CAAA;AAGnD,EAAM,MAAA,yBAAA,GAA4B,GAAG,MAAM,CAAA,UAAA,CAAA,CAAA;AAE3C,EAAO,OAAA;AAAA,IACL,oBAAA;AAAA,IACA,oBAAA;AAAA,IACA,yBAAA;AAAA,IACA,iBAAA;AAAA,GACF,CAAA;AACF,CAAA;;ACkDA,MAAM,cAAc,GAAO,GAAA,EAAA,CAAA;AAO3B,eAAsB,aACpB,OACyB,EAAA;AACzB,EAAA,MAAM,EAAE,IAAA,EAAM,QAAS,EAAA,GAAIC,uCAAyB,OAAO,CAAA,CAAA;AAC3D,EAAA,MAAM,EAAE,MAAA,EAAQ,MAAQ,EAAA,SAAA,EAAc,GAAA,OAAA,CAAA;AACtC,EAAA,MAAMC,kBAAgB,IAAIC,2BAAA,CAAc,EAAE,YAAA,EAAc,WAAW,CAAA,CAAA;AACnE,EAAA,MAAA,CAAO,KAAK,qCAAqC,CAAA,CAAA;AAEjD,EAAA,MAAM,cACJC,0BAAa,CAAA,UAAA,CAAW,MAAM,CAAA,CAAE,UAAU,gBAAgB,CAAA,CAAA;AAC5D,EAAA,MAAM,QAAQ,WAAY,CAAA,SAAA,CAAU,EAAE,UAAA,EAAY,aAAa,CAAA,CAAA;AAE/D,EAAA,MAAM,SAASC,uBAAO,EAAA,CAAA;AACtB,EAAO,MAAA,CAAA,GAAA,CAAIC,wBAAQ,CAAA,IAAA,EAAM,CAAA,CAAA;AAEzB,EAAA,MAAA,CAAO,GAAI,CAAA,SAAA,EAAW,CAAC,CAAA,EAAG,QAAa,KAAA;AACrC,IAAA,QAAA,CAAS,IAAK,CAAA,EAAE,MAAQ,EAAA,IAAA,EAAM,CAAA,CAAA;AAAA,GAC/B,CAAA,CAAA;AAED,EAAO,MAAA,CAAA,GAAA;AAAA,IACL,kDAAA;AAAA,IACA,OAAO,SAAS,QAAa,KAAA;AAtGjC,MAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,CAAA;AAuGM,MAAA,MAAM,EAAE,IAAA,EAAM,SAAW,EAAA,IAAA,KAAS,OAAQ,CAAA,MAAA,CAAA;AAC1C,MAAA,MAAM,YAAYC,+BAAmB,CAAA,EAAE,IAAM,EAAA,SAAA,EAAW,MAAM,CAAA,CAAA;AAC9D,MAAA,MAAM,EAAE,KAAA,EAAU,GAAA,MAAM,KAAK,qBAAsB,CAAA;AAAA,QACjD,UAAA,EAAY,MAAM,IAAA,CAAK,wBAAyB,EAAA;AAAA,QAChD,cAAgB,EAAA,SAAA;AAAA,OACjB,CAAA,CAAA;AACD,MAAA,MAAM,SAAS,MAAML,eAAA,CAAc,eAAe,SAAW,EAAA,EAAE,OAAO,CAAA,CAAA;AACtE,MAAM,MAAA;AAAA,QACJ,oBAAA;AAAA,QACA,oBAAA;AAAA,QACA,yBAAA;AAAA,QACA,iBAAA;AAAA,OACF,GAAI,eAAe,MAAM,CAAA,CAAA;AAEzB,MAAA,IAAI,CAAC,MAAQ,EAAA;AACX,QAAO,MAAA,CAAA,IAAA,CAAK,CAAuB,oBAAA,EAAA,SAAS,CAAE,CAAA,CAAA,CAAA;AAC9C,QACG,QAAA,CAAA,MAAA,CAAO,GAAG,CACV,CAAA,IAAA,CAAK,EAAE,KAAO,EAAA,CAAA,oBAAA,EAAuB,SAAS,CAAA,CAAA,EAAI,CAAA,CAAA;AACrD,QAAA,OAAA;AAAA,OACF;AAEA,MAAA,MAAM,cACJ,EAAO,GAAA,CAAA,EAAA,GAAA,MAAA,CAAA,QAAA,CAAS,gBAAhB,IAA8B,GAAA,KAAA,CAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,KAA9B,mBAAqD,KAAM,CAAA,GAAA,CAAA,CAAA;AAE7D,MAAA,IAAI,CAAC,UAAY,EAAA;AACf,QAAM,MAAA,KAAA,GAAQ,gDAAgD,SAAS,CAAA,CAAA,CAAA;AACvE,QAAA,MAAA,CAAO,KAAK,KAAK,CAAA,CAAA;AACjB,QAAA,QAAA,CAAS,MAAO,CAAA,GAAG,CAAE,CAAA,IAAA,CAAK,KAAK,CAAA,CAAA;AAC/B,QAAA,OAAA;AAAA,OACF;AAEA,MAAI,IAAA,eAAA,CAAA;AAEJ,MAAI,IAAA;AACF,QAAA,eAAA,GAAkB,MAAM,kBAAA;AAAA,UACtB,WAAW,CAAC,CAAA;AAAA,UACZ,MAAA;AAAA,UACA,KAAA;AAAA,SACF,CAAA;AAAA,eACO,GAAK,EAAA;AACZ,QAAA,MAAA,CAAO,KAAM,CAAA,CAAA,4BAAA,EAA+B,UAAW,CAAA,CAAC,CAAC,CAAE,CAAA,CAAA,CAAA;AAC3D,QAAS,QAAA,CAAA,MAAA,CAAO,GAAG,CAAA,CAAE,IAAK,CAAA;AAAA,UACxB,KAAO,EAAA,CAAA,+BAAA,EAAkC,UAAW,CAAA,CAAC,CAAC,CAAA,CAAA;AAAA,SACvD,CAAA,CAAA;AACD,QAAA,OAAA;AAAA,OACF;AAEA,MAAA,MAAM,WAAc,GAAA,MAAM,QAAS,CAAA,WAAA,CAAY,OAAS,EAAA;AAAA,QACtD,KAAA,EAAO,CAAC,MAAM,CAAA;AAAA,OACf,CAAA,CAAA;AAED,MAAM,MAAA,aAAA,GAAgB,YAAY,SAAU,CAAA,aAAA,CAAA;AAE5C,MAAA,IAAI,CAAC,aAAe,EAAA;AAClB,QAAA,MAAA,CAAO,KAAK,CAA8B,4BAAA,CAAA,CAAA,CAAA;AAAA,OAC5C;AAEA,MAAA,IAAI,UAAoB,EAAC,CAAA;AAEzB,MAAA,MAAM,2BACJ,EAAO,GAAA,CAAA,EAAA,GAAA,MAAA,CAAA,QAAA,CAAS,gBAAhB,IAA8B,GAAA,KAAA,CAAA,GAAA,EAAA,CAAA,iBAAA,CAAA,KAA9B,mBAAkD,KAAM,CAAA,GAAA,CAAA,CAAA;AAE1D,MAAU,OAAA,GAAA,iBAAA,CAAkB,QAAQ,aAAa,CAAA,CAAA;AAEjD,MAAA,IAAI,uBAAyB,EAAA;AAC3B,QAAQ,OAAA,CAAA,IAAA;AAAA,UACN,GAAI,MAAM,yBAA0B,CAAA,uBAAA,EAAyB,MAAM,CAAA;AAAA,SACrE,CAAA;AAAA,OACF;AAEA,MAAI,IAAA,UAAA,GAAA,CACF,EAAO,GAAA,CAAA,EAAA,GAAA,CAAA,EAAA,GAAA,MAAA,CAAA,QAAA,CAAS,WAAhB,KAAA,IAAA,GAAA,KAAA,CAAA,GAAA,EAAA,CAA8B,0BAA9B,IAAqD,GAAA,KAAA,CAAA,GAAA,EAAA,CAAA,KAAA,CAAM,GAA3D,CAAA,KAAA,IAAA,GAAA,EAAA,GAAmE,EAAC,CAAA;AACtE,MAAA,IAAI,SAAS,MAAM,oBAAA;AAAA,QACjB,WAAW,CAAC,CAAA;AAAA,QACZ,UAAA;AAAA,QACA,OAAA;AAAA,QACA,MAAA;AAAA,OACF,CAAA;AAGA,MAAA,UAAA,GAAa,UAAW,CAAA,MAAA;AAAA,QACtB,CAAA,EAAA,GAAA,CAAA,EAAA,GAAA,CAAA,EAAA,GAAA,MAAA,CAAO,SAAS,WAAhB,KAAA,IAAA,GAAA,KAAA,CAAA,GAAA,EAAA,CAA8B,+BAA9B,IAA0D,GAAA,KAAA,CAAA,GAAA,EAAA,CAAA,KAAA,CAAM,GAAhE,CAAA,KAAA,IAAA,GAAA,EAAA,GACE,EAAC;AAAA,OACL,CAAA;AAEA,MAAA,IAAI,UAAY,EAAA;AACd,QAAA,MAAM,kBAAkB,MAAM,uBAAA;AAAA,UAC5B,WAAW,CAAC,CAAA;AAAA,UACZ,UAAA;AAAA,UACA,MAAA;AAAA,SACF,CAAA;AACA,QAAS,MAAA,GAAA,MAAA,CAAO,OAAO,eAAe,CAAA,CAAA;AAAA,OACxC;AAEA,MAAA,MAAM,YAA6B,GAAA;AAAA,QACjC,OAAS,EAAA,eAAA;AAAA,QACT,IAAM,EAAA,MAAA;AAAA,OACR,CAAA;AACA,MAAA,QAAA,CAAS,KAAK,YAAY,CAAA,CAAA;AAAA,KAC5B;AAAA,GACF,CAAA;AAEA,EAAO,MAAA,CAAA,GAAA;AAAA,IACL,8CAAA;AAAA,IACA,OAAO,SAAS,QAAa,KAAA;AAhNjC,MAAA,IAAA,EAAA,EAAA,EAAA,CAAA;AAiNM,MAAA,MAAM,EAAE,IAAA,EAAM,SAAW,EAAA,IAAA,KAAS,OAAQ,CAAA,MAAA,CAAA;AAC1C,MAAA,MAAM,YAAYK,+BAAmB,CAAA,EAAE,IAAM,EAAA,SAAA,EAAW,MAAM,CAAA,CAAA;AAC9D,MAAA,MAAM,EAAE,KAAA,EAAU,GAAA,MAAM,KAAK,qBAAsB,CAAA;AAAA,QACjD,UAAA,EAAY,MAAM,IAAA,CAAK,wBAAyB,EAAA;AAAA,QAChD,cAAgB,EAAA,SAAA;AAAA,OACjB,CAAA,CAAA;AACD,MAAA,MAAM,SAAS,MAAML,eAAA,CAAc,eAAe,SAAW,EAAA,EAAE,OAAO,CAAA,CAAA;AACtE,MAAA,MAAM,EAAE,oBAAA,EAAyB,GAAA,cAAA,CAAe,MAAM,CAAA,CAAA;AAEtD,MAAA,IAAI,CAAC,MAAQ,EAAA;AACX,QAAO,MAAA,CAAA,IAAA,CAAK,CAAuB,oBAAA,EAAA,SAAS,CAAE,CAAA,CAAA,CAAA;AAC9C,QACG,QAAA,CAAA,MAAA,CAAO,GAAG,CACV,CAAA,IAAA,CAAK,EAAE,KAAO,EAAA,CAAA,oBAAA,EAAuB,SAAS,CAAA,CAAA,EAAI,CAAA,CAAA;AACrD,QAAA,OAAA;AAAA,OACF;AAEA,MAAA,MAAM,cACJ,EAAO,GAAA,CAAA,EAAA,GAAA,MAAA,CAAA,QAAA,CAAS,gBAAhB,IAA8B,GAAA,KAAA,CAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,KAA9B,mBAAqD,KAAM,CAAA,GAAA,CAAA,CAAA;AAE7D,MAAA,MAAM,kBAAkB,MAAM,kBAAA;AAAA,QAC5B,WAAW,CAAC,CAAA;AAAA,QACZ,MAAA;AAAA,QACA,KAAA;AAAA,OACF,CAAA;AAEA,MAAA,IAAI,CAAC,eAAiB,EAAA;AACpB,QAAA,MAAA,CAAO,MAAM,gCAAgC,CAAA,CAAA;AAC7C,QAAS,QAAA,CAAA,MAAA,CAAO,GAAG,CAAA,CAAE,IAAK,CAAA;AAAA,UACxB,KAAO,EAAA,CAAA,sCAAA,EAAyC,UAAW,CAAA,CAAC,CAAC,CAAA,CAAA;AAAA,SAC9D,CAAA,CAAA;AACD,QAAA,OAAA;AAAA,OACF;AAEA,MAAM,MAAA,GAAA,GAAM,eAAgB,CAAA,UAAA,CAAW,OAAO,CAAA,CAAA;AAE9C,MAAA,MAAM,MAAS,GAAA,MAAM,gBAAiB,CAAA,GAAA,EAAK,MAAM,CAAA,CAAA;AAEjD,MAAM,MAAA,EAAA,GAAK,IAAIM,uBAAA,CAAO,WAAY,EAAA,CAAA;AAClC,MAAA,MAAM,GAAM,GAAA,MAAA,CAAO,OAAQ,CAAA,GAAA,CAAI,cAAc,CAAA,CAAA;AAE7C,MAAS,QAAA,CAAA,SAAA,CAAU,cAAgB,EAAA,GAAA,IAAA,IAAA,GAAA,GAAA,GAAO,EAAE,CAAA,CAAA;AAC5C,MAAAA,uBAAA,CAAO,QAAS,CAAA,MAAA,CAAO,IAAM,EAAA,EAAA,EAAI,CAAO,GAAA,KAAA;AACtC,QAAA,IAAI,GAAK,EAAA;AACP,UAAA,MAAA,CAAO,MAAM,GAAG,CAAA,CAAA;AAChB,UAAA,QAAA,CAAS,WAAW,GAAG,CAAA,CAAA;AAAA,SACzB;AACA,QAAA,OAAA;AAAA,OACD,CAAA,CAAA;AACD,MAAA,EAAA,CAAG,KAAK,QAAQ,CAAA,CAAA;AAAA,KAClB;AAAA,GACF,CAAA;AACA,EAAO,MAAA,CAAA,GAAA,CAAIC,4BAAc,CAAA,CAAA;AACzB,EAAO,OAAA,MAAA,CAAA;AACT;;AC3PO,MAAM,sBAAsBC,oCAAoB,CAAA;AAAA,EACrD,QAAU,EAAA,gBAAA;AAAA,EACV,SAAS,GAAK,EAAA;AACZ,IAAA,GAAA,CAAI,YAAa,CAAA;AAAA,MACf,IAAM,EAAA;AAAA,QACJ,QAAQC,6BAAa,CAAA,MAAA;AAAA,QACrB,QAAQA,6BAAa,CAAA,UAAA;AAAA,QACrB,WAAWA,6BAAa,CAAA,SAAA;AAAA,QACxB,YAAYA,6BAAa,CAAA,UAAA;AAAA,QACzB,MAAMA,6BAAa,CAAA,IAAA;AAAA,QACnB,UAAUA,6BAAa,CAAA,QAAA;AAAA,OACzB;AAAA,MACA,MAAM,KAAK,EAAE,MAAA,EAAQ,QAAQ,SAAW,EAAA,UAAA,EAAY,IAAM,EAAA,QAAA,EAAY,EAAA;AACpE,QAAW,UAAA,CAAA,GAAA;AAAA,UACT,MAAM,YAAa,CAAA;AAAA,YACjB,MAAA,EAAQC,oCAAsB,MAAM,CAAA;AAAA,YACpC,MAAA;AAAA,YACA,SAAA;AAAA,YACA,IAAA;AAAA,YACA,QAAA;AAAA,WACD,CAAA;AAAA,SACH,CAAA;AAAA,OACF;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AACF,CAAC;;;;;;"}
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":["../src/config.ts","../src/filters.ts","../src/queries.ts","../src/api.ts","../src/service/service.ts","../src/lib.ts","../src/service/router.ts","../src/plugin.ts"],"sourcesContent":["import { Config } from '@backstage/config';\n\nconst JIRA_BASE_URL_CONFIG_PATH = 'jiraDashboard.baseUrl';\nconst JIRA_TOKEN_CONFIG_PATH = 'jiraDashboard.token';\nconst JIRA_USER_CONFIG_EMAIL_SUFFIX = 'jiraDashboard.userEmailSuffix';\nconst JIRA_ANNOTATION = 'jiraDashboard.annotationPrefix';\n\nexport function resolveJiraBaseUrl(config: Config): string {\n try {\n return config.getString(JIRA_BASE_URL_CONFIG_PATH);\n } catch (error) {\n throw new Error(`Invalid Jira baseUrl, ${error}`);\n }\n}\n\nexport function resolveJiraToken(config: Config): string {\n try {\n return config.getString(JIRA_TOKEN_CONFIG_PATH);\n } catch (error) {\n throw new Error(`Invalid Jira token, ${error}`);\n }\n}\n\nexport function resolveUserEmailSuffix(config: Config): string | undefined {\n return config.getOptionalString(JIRA_USER_CONFIG_EMAIL_SUFFIX);\n}\n\nexport function resolveAnnotationPrefix(config: Config): string {\n const annotationPrefix = config.getOptionalString(JIRA_ANNOTATION);\n return annotationPrefix ?? 'jira.com';\n}\n","import { Config } from '@backstage/config';\nimport { resolveUserEmailSuffix } from './config';\nimport { Filter } from '@axis-backstage/plugin-jira-dashboard-common';\nimport { UserEntity } from '@backstage/catalog-model';\n\nconst openFilter: Filter = {\n name: 'Open Issues',\n shortName: 'OPEN',\n query: 'resolution = Unresolved ORDER BY updated DESC',\n};\n\nconst getIncomingFilter = (incomingStatus: string): Filter => ({\n name: 'Incoming Issues',\n shortName: 'INCOMING',\n query: `status = ${incomingStatus} ORDER BY created ASC`,\n});\n\nconst getAssignedToMeFilter = (\n userEntity: UserEntity,\n config: Config,\n): Filter => {\n const emailSuffixConfig = resolveUserEmailSuffix(config);\n\n const email = emailSuffixConfig\n ? `${userEntity.metadata.name}${emailSuffixConfig}`\n : userEntity.spec?.profile?.email;\n\n return {\n name: 'Assigned to me',\n shortName: 'ME',\n query: `assignee = \"${email}\" AND resolution = Unresolved ORDER BY updated DESC`,\n };\n};\n\nexport const getDefaultFiltersForUser = (\n config: Config,\n userEntity?: UserEntity,\n incomingStatus?: string,\n): Filter[] => {\n const incomingFilter = getIncomingFilter(incomingStatus ?? 'New');\n\n if (!userEntity) return [openFilter, incomingFilter];\n\n const assigneeToMeFilter = getAssignedToMeFilter(userEntity, config);\n\n return [openFilter, incomingFilter, assigneeToMeFilter];\n};\n","/**\n * Types for the arguments to the jqlQueryBuilder function.\n *\n * @public\n */\nexport type JqlQueryBuilderArgs = {\n project: string;\n components?: string[];\n query?: string;\n};\n\n/**\n * Creates a jql query string.\n *\n * @public\n */\nexport const jqlQueryBuilder = ({\n project,\n components,\n query,\n}: JqlQueryBuilderArgs) => {\n let jql = `project in (${project})`;\n if (components && components.length > 0) {\n let componentsInclude = '(';\n for (let index = 0; index < components.length; index++) {\n const component = components[index];\n componentsInclude += `'${component}'`;\n // Add either the \",\" separator or close the parentheses.\n if (index === components.length - 1) {\n componentsInclude += ')';\n } else {\n componentsInclude += ',';\n }\n }\n jql += ` AND component in ${componentsInclude}`;\n }\n if (query) {\n jql += ` AND ${query}`;\n }\n return jql;\n};\n","import { Config } from '@backstage/config';\nimport fetch from 'node-fetch';\nimport {\n Filter,\n Issue,\n Project,\n} from '@axis-backstage/plugin-jira-dashboard-common';\nimport { resolveJiraBaseUrl, resolveJiraToken } from './config';\nimport { jqlQueryBuilder } from './queries';\n\nexport const getProjectInfo = async (\n projectKey: string,\n config: Config,\n): Promise<Project> => {\n const response = await fetch(\n `${resolveJiraBaseUrl(config)}project/${projectKey}`,\n {\n method: 'GET',\n headers: {\n Authorization: resolveJiraToken(config),\n Accept: 'application/json',\n },\n },\n );\n if (response.status !== 200) {\n throw Error(\n `Request failed with status code ${response.status}: ${response.statusText}`,\n );\n }\n return response.json();\n};\n\nexport const getFilterById = async (\n id: string,\n config: Config,\n): Promise<Filter> => {\n const response = await fetch(`${resolveJiraBaseUrl(config)}filter/${id}`, {\n method: 'GET',\n headers: {\n Authorization: resolveJiraToken(config),\n Accept: 'application/json',\n },\n });\n if (response.status !== 200) {\n throw Error(`${response.status}`);\n }\n const jsonResponse = await response.json();\n return { name: jsonResponse.name, query: jsonResponse.jql } as Filter;\n};\n\nexport const getIssuesByFilter = async (\n projectKey: string,\n components: string[],\n query: string,\n config: Config,\n): Promise<Issue[]> => {\n const jql = jqlQueryBuilder({ project: projectKey, components, query });\n const response = await fetch(\n `${resolveJiraBaseUrl(config)}search?jql=${jql}`,\n {\n method: 'GET',\n headers: {\n Authorization: resolveJiraToken(config),\n Accept: 'application/json',\n },\n },\n ).then(resp => resp.json());\n return response.issues;\n};\n\n/**\n * Options available for the Jira JQL query.\n *\n * @public\n */\nexport type SearchOptions = {\n expand?: string[];\n fields?: string[];\n fieldsByKey?: boolean;\n properties?: string[];\n startAt?: number;\n maxResults?: number;\n validateQuery?: string;\n};\n\n/**\n * Search for Jira issues using JQL.\n *\n * For more information about the available options see the API\n * documentation at:\n * https://developer.atlassian.com/cloud/jira/platform/rest/v2/api-group-issue-search/#api-rest-api-2-search-post\n *\n * @param config - A Backstage config\n * @param jqlQuery - A string containing the jql query.\n * @param options - Query options that will be passed on to the POST request.\n *\n * @public\n */\nexport const searchJira = async (\n config: Config,\n jqlQuery: string,\n options: SearchOptions,\n): Promise<Issue[]> => {\n const response = await fetch(`${resolveJiraBaseUrl(config)}search`, {\n method: 'POST',\n body: JSON.stringify({ jql: jqlQuery, ...options }),\n headers: {\n Authorization: resolveJiraToken(config),\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n },\n }).then(resp => resp.json());\n return response.issues;\n};\n\nexport const getIssuesByComponent = async (\n projectKey: string,\n componentKey: string,\n config: Config,\n): Promise<Issue[]> => {\n const jql = jqlQueryBuilder({\n project: projectKey,\n components: [componentKey],\n });\n const response = await fetch(\n `${resolveJiraBaseUrl(config)}search?jql=${jql}`,\n {\n method: 'GET',\n headers: {\n Authorization: resolveJiraToken(config),\n Accept: 'application/json',\n },\n },\n ).then(resp => resp.json());\n return response.issues;\n};\n\nexport async function getProjectAvatar(url: string, config: Config) {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n Authorization: resolveJiraToken(config),\n },\n });\n return response;\n}\n","import { CacheClient } from '@backstage/backend-common';\nimport { Config } from '@backstage/config';\nimport {\n type Filter,\n type JiraDataResponse,\n type Project,\n} from '@axis-backstage/plugin-jira-dashboard-common';\nimport {\n getFilterById,\n getIssuesByComponent,\n getIssuesByFilter,\n getProjectInfo,\n} from '../api';\n\nexport const getProjectResponse = async (\n projectKey: string,\n config: Config,\n cache: CacheClient,\n): Promise<Project> => {\n let projectResponse: Project;\n\n projectResponse = (await cache.get(projectKey)) as Project;\n\n if (projectResponse) return projectResponse as Project;\n\n try {\n projectResponse = await getProjectInfo(projectKey, config);\n cache.set(projectKey, projectResponse);\n } catch (err: any) {\n if (err.message !== 200) {\n throw Error(\n `Failed to get project info for project key ${projectKey} with error: ${err.message}`,\n );\n }\n }\n return projectResponse;\n};\n\nexport const getFiltersFromAnnotations = async (\n annotations: string[],\n config: Config,\n): Promise<Filter[]> => {\n const filters: Filter[] = [];\n\n for (const filter of annotations) {\n try {\n const response = await getFilterById(filter, config);\n filters.push(response);\n } catch (err: any) {\n console.warn(\n `${err.message} : Could not find filter with filter id ${filter}`,\n );\n }\n }\n return filters;\n};\n\nexport const getIssuesFromFilters = async (\n projectKey: string,\n components: string[],\n filters: Filter[],\n config: Config,\n): Promise<JiraDataResponse[]> => {\n return await Promise.all(\n filters.map(async filter => ({\n name: filter.name,\n type: 'filter',\n issues: await getIssuesByFilter(\n projectKey,\n components,\n filter.query,\n config,\n ),\n })),\n );\n};\n\nexport const getIssuesFromComponents = async (\n projectKey: string,\n componentAnnotations: string[],\n config: Config,\n): Promise<JiraDataResponse[]> => {\n return await Promise.all(\n componentAnnotations.map(async componentKey => ({\n name: componentKey,\n type: 'component',\n issues: await getIssuesByComponent(projectKey, componentKey, config),\n })),\n );\n};\n","import { resolveAnnotationPrefix } from './config';\nimport {\n COMPONENTS_NAME,\n PROJECT_KEY_NAME,\n FILTERS_NAME,\n INCOMING_ISSUES_STATUS,\n} from '@axis-backstage/plugin-jira-dashboard-common';\nimport { Config } from '@backstage/config';\n\nexport const getAnnotations = (config: Config) => {\n const prefix = resolveAnnotationPrefix(config);\n\n const projectKeyAnnotation = `${prefix}/${PROJECT_KEY_NAME}`;\n const componentsAnnotation = `${prefix}/${COMPONENTS_NAME}`;\n const filtersAnnotation = `${prefix}/${FILTERS_NAME}`;\n const incomingIssuesAnnotation = `${prefix}/${INCOMING_ISSUES_STATUS}`;\n\n /* Adding support for Roadie's component annotation */\n const componentRoadieAnnotation = `${prefix}/component`;\n\n return {\n projectKeyAnnotation,\n componentsAnnotation,\n filtersAnnotation,\n incomingIssuesAnnotation,\n componentRoadieAnnotation,\n };\n};\n","import {\n CacheManager,\n TokenManager,\n createLegacyAuthAdapters,\n errorHandler,\n} from '@backstage/backend-common';\nimport {\n AuthService,\n DiscoveryService,\n HttpAuthService,\n} from '@backstage/backend-plugin-api';\nimport { UserEntity, stringifyEntityRef } from '@backstage/catalog-model';\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { Config } from '@backstage/config';\nimport { Logger } from 'winston';\nimport { CatalogClient } from '@backstage/catalog-client';\nimport { IdentityApi } from '@backstage/plugin-auth-node';\n\nimport { getDefaultFiltersForUser } from '../filters';\nimport {\n type Filter,\n type JiraResponse,\n type Project,\n} from '@axis-backstage/plugin-jira-dashboard-common';\nimport stream from 'stream';\nimport { getProjectAvatar } from '../api';\nimport {\n getProjectResponse,\n getFiltersFromAnnotations,\n getIssuesFromFilters,\n getIssuesFromComponents,\n} from './service';\nimport { getAnnotations } from '../lib';\n\n/**\n * Constructs a jira dashboard router.\n * @public\n */\nexport interface RouterOptions {\n /**\n * Implementation of Winston logger\n */\n logger: Logger;\n\n /**\n * Backstage config object\n */\n config: Config;\n\n /**\n * Backstage discovery api instance\n */\n discovery: DiscoveryService;\n\n /**\n * Backstage identity api instance\n */\n identity?: IdentityApi;\n\n /**\n * Backstage token manager instance\n */\n tokenManager?: TokenManager;\n /**\n * Backstage auth service\n */\n auth?: AuthService;\n /**\n * Backstage httpAuth service\n */\n httpAuth?: HttpAuthService;\n}\n\nconst DEFAULT_TTL = 1000 * 60;\n\n/**\n * Constructs a jira dashboard router.\n *\n * @public\n */\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const { auth, httpAuth } = createLegacyAuthAdapters(options);\n const { logger, config, discovery } = options;\n const catalogClient = new CatalogClient({ discoveryApi: discovery });\n logger.info('Initializing Jira Dashboard backend');\n\n const pluginCache =\n CacheManager.fromConfig(config).forPlugin('jira-dashboard');\n const cache = pluginCache.getClient({ defaultTtl: DEFAULT_TTL });\n\n const router = Router();\n router.use(express.json());\n\n router.get('/health', (_, response) => {\n response.json({ status: 'ok' });\n });\n\n router.get(\n '/dashboards/by-entity-ref/:kind/:namespace/:name',\n async (request, response) => {\n const { kind, namespace, name } = request.params;\n const entityRef = stringifyEntityRef({ kind, namespace, name });\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n const entity = await catalogClient.getEntityByRef(entityRef, { token });\n const {\n projectKeyAnnotation,\n componentsAnnotation,\n filtersAnnotation,\n incomingIssuesAnnotation,\n componentRoadieAnnotation,\n } = getAnnotations(config);\n\n if (!entity) {\n logger.info(`No entity found for ${entityRef}`);\n response\n .status(500)\n .json({ error: `No entity found for ${entityRef}` });\n return;\n }\n\n const projectKey =\n entity.metadata.annotations?.[projectKeyAnnotation]?.split(',')!;\n\n if (!projectKey) {\n const error = `No jira.com/project-key annotation found for ${entityRef}`;\n logger.info(error);\n response.status(404).json(error);\n return;\n }\n\n let projectResponse;\n\n try {\n projectResponse = await getProjectResponse(\n projectKey[0],\n config,\n cache,\n );\n } catch (err: any) {\n logger.error(\n `Could not find Jira project ${projectKey[0]}: ${err.message}`,\n );\n response.status(404).json({\n error: `No Jira project found with key ${projectKey[0]}`,\n });\n return;\n }\n\n let userEntity: UserEntity | undefined;\n\n try {\n const credentials = await httpAuth.credentials(request, {\n allow: ['user'],\n });\n const userIdentity = credentials.principal.userEntityRef;\n\n userEntity = (await catalogClient.getEntityByRef(userIdentity, {\n token,\n })) as UserEntity;\n } catch (err) {\n logger.warn('Could not find user identity');\n }\n\n let filters: Filter[] = [];\n\n const incomingStatus =\n entity.metadata.annotations?.[incomingIssuesAnnotation];\n\n filters = getDefaultFiltersForUser(config, userEntity, incomingStatus);\n\n const customFilterAnnotations =\n entity.metadata.annotations?.[filtersAnnotation]?.split(',')!;\n\n if (customFilterAnnotations) {\n filters.push(\n ...(await getFiltersFromAnnotations(customFilterAnnotations, config)),\n );\n }\n\n let components =\n entity.metadata.annotations?.[componentsAnnotation]?.split(',') ?? [];\n let issues = await getIssuesFromFilters(\n projectKey[0],\n components,\n filters,\n config,\n );\n\n /* Adding support for Roadie's component annotation */\n components = components.concat(\n entity.metadata.annotations?.[componentRoadieAnnotation]?.split(',') ??\n [],\n );\n\n if (components) {\n const componentIssues = await getIssuesFromComponents(\n projectKey[0],\n components,\n config,\n );\n issues = issues.concat(componentIssues);\n }\n\n const jiraResponse: JiraResponse = {\n project: projectResponse as Project,\n data: issues,\n };\n response.json(jiraResponse);\n },\n );\n\n router.get(\n '/avatar/by-entity-ref/:kind/:namespace/:name',\n async (request, response) => {\n const { kind, namespace, name } = request.params;\n const entityRef = stringifyEntityRef({ kind, namespace, name });\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n const entity = await catalogClient.getEntityByRef(entityRef, { token });\n const { projectKeyAnnotation } = getAnnotations(config);\n\n if (!entity) {\n logger.info(`No entity found for ${entityRef}`);\n response\n .status(500)\n .json({ error: `No entity found for ${entityRef}` });\n return;\n }\n\n const projectKey =\n entity.metadata.annotations?.[projectKeyAnnotation]?.split(',')!;\n\n const projectResponse = await getProjectResponse(\n projectKey[0],\n config,\n cache,\n );\n\n if (!projectResponse) {\n logger.error('Could not find project in Jira');\n response.status(400).json({\n error: `No Jira project found for project key ${projectKey[0]}`,\n });\n return;\n }\n\n const url = projectResponse.avatarUrls['48x48'];\n\n const avatar = await getProjectAvatar(url, config);\n\n const ps = new stream.PassThrough();\n const val = avatar.headers.get('content-type');\n\n response.setHeader('content-type', val ?? '');\n stream.pipeline(avatar.body, ps, err => {\n if (err) {\n logger.error(err);\n response.sendStatus(400);\n }\n return;\n });\n ps.pipe(response);\n },\n );\n router.use(errorHandler());\n return router;\n}\n","import { loggerToWinstonLogger } from '@backstage/backend-common';\nimport {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { createRouter } from './service/router';\n\n/**\n * The Jira Dashboard backend plugin.\n *\n * @public\n */\nexport const jiraDashboardPlugin = createBackendPlugin({\n pluginId: 'jira-dashboard',\n register(env) {\n env.registerInit({\n deps: {\n logger: coreServices.logger,\n config: coreServices.rootConfig,\n discovery: coreServices.discovery,\n httpRouter: coreServices.httpRouter,\n auth: coreServices.auth,\n httpAuth: coreServices.httpAuth,\n },\n async init({ logger, config, discovery, httpRouter, auth, httpAuth }) {\n httpRouter.use(\n await createRouter({\n logger: loggerToWinstonLogger(logger),\n config,\n discovery,\n auth,\n httpAuth,\n }),\n );\n },\n });\n },\n});\n"],"names":["fetch","PROJECT_KEY_NAME","COMPONENTS_NAME","FILTERS_NAME","INCOMING_ISSUES_STATUS","createLegacyAuthAdapters","catalogClient","CatalogClient","CacheManager","Router","express","stringifyEntityRef","stream","errorHandler","createBackendPlugin","coreServices","loggerToWinstonLogger"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -84,4 +84,21 @@ type SearchOptions = {
|
|
|
84
84
|
*/
|
|
85
85
|
declare const searchJira: (config: Config, jqlQuery: string, options: SearchOptions) => Promise<Issue[]>;
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Types for the arguments to the jqlQueryBuilder function.
|
|
89
|
+
*
|
|
90
|
+
* @public
|
|
91
|
+
*/
|
|
92
|
+
type JqlQueryBuilderArgs = {
|
|
93
|
+
project: string;
|
|
94
|
+
components?: string[];
|
|
95
|
+
query?: string;
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Creates a jql query string.
|
|
99
|
+
*
|
|
100
|
+
* @public
|
|
101
|
+
*/
|
|
102
|
+
declare const jqlQueryBuilder: ({ project, components, query, }: JqlQueryBuilderArgs) => string;
|
|
103
|
+
|
|
104
|
+
export { type JqlQueryBuilderArgs, type RouterOptions, type SearchOptions, createRouter, jiraDashboardPlugin as default, jqlQueryBuilder, searchJira };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axis-backstage/plugin-jira-dashboard-backend",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"main": "dist/index.cjs.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"postpack": "backstage-cli package postpack"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@axis-backstage/plugin-jira-dashboard-common": "^1.0
|
|
26
|
+
"@axis-backstage/plugin-jira-dashboard-common": "^1.1.0",
|
|
27
27
|
"@backstage/backend-common": "^0.21.7",
|
|
28
28
|
"@backstage/backend-plugin-api": "^0.6.17",
|
|
29
29
|
"@backstage/catalog-client": "^1.6.4",
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
"yn": "^4.0.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
+
"@backstage/backend-test-utils": "^0.3.8",
|
|
42
43
|
"@backstage/cli": "^0.26.3",
|
|
43
44
|
"@types/supertest": "^2.0.12",
|
|
44
45
|
"msw": "^1.0.0",
|