Skip to content

Commit 3aefac4

Browse files
committed
feat(cc-addon-info.smart-jenkins): init
1 parent 81d81d3 commit 3aefac4

File tree

6 files changed

+236
-0
lines changed

6 files changed

+236
-0
lines changed

demo-smart/index.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,11 @@
238238
>cc-addon-header.smart-jenkins</a
239239
>
240240
</li>
241+
<li>
242+
<a class="definition-link" href="?definition=cc-addon-info.smart-jenkins&smart-mode=jenkins"
243+
>cc-addon-info.smart-jenkins</a
244+
>
245+
</li>
241246
</ul>
242247

243248
<div class="context-buttons">
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
import { defineSmartComponent } from '../../lib/smart/define-smart-component.js';
2+
// @ts-expect-error FIXME: remove when clever-client exports types
3+
import { getAddon as getAddonProvider } from '@clevercloud/client/esm/api/v2/providers.js';
4+
// @ts-expect-error FIXME: remove when clever-client exports types
5+
import { ONE_SECOND } from '@clevercloud/client/esm/with-cache.js';
6+
import { getDocUrl } from '../../lib/dev-hub-url.js';
7+
import { formatAddonFeatures } from '../../lib/product.js';
8+
import { sendToApi } from '../../lib/send-to-api.js';
9+
import { i18n } from '../../translations/translation.js';
10+
import '../cc-smart-container/cc-smart-container.js';
11+
import { CcAddonInfoClient } from './cc-addon-info.client.js';
12+
import './cc-addon-info.js';
13+
14+
const PROVIDER_ID = 'jenkins';
15+
16+
/**
17+
* @typedef {import('./cc-addon-info.js').CcAddonInfo} CcAddonInfo
18+
* @typedef {import('./cc-addon-info.types.js').AddonInfoStateLoading} AddonInfoStateLoading
19+
* @typedef {import('./cc-addon-info.types.js').JenkinsProviderInfo} JenkinsProviderInfo
20+
* @typedef {import('./cc-addon-info.types.js').RawAddon} RawAddon
21+
* @typedef {import('../../lib/smart/smart-component.types.js').OnContextUpdateArgs<CcAddonInfo>} OnContextUpdateArgs
22+
* @typedef {import('../../lib/send-to-api.types.js').ApiConfig} ApiConfig
23+
* @typedef {import('../../lib/send-to-api.types.js').AuthBridgeConfig} AuthBridgeConfig
24+
*/
25+
26+
defineSmartComponent({
27+
selector: 'cc-addon-info[smart-mode="jenkins"]',
28+
params: {
29+
apiConfig: { type: Object },
30+
ownerId: { type: String },
31+
addonId: { type: String },
32+
},
33+
/**
34+
* @param {OnContextUpdateArgs} _
35+
*/
36+
onContextUpdate({ context, updateComponent, signal }) {
37+
const { apiConfig, ownerId, addonId } = context;
38+
39+
const api = new Api({ apiConfig, ownerId, addonId, signal });
40+
41+
/**
42+
* @type {AddonInfoStateLoading}
43+
*/
44+
const LOADING_STATE = {
45+
type: 'loading',
46+
version: {
47+
stateType: 'up-to-date',
48+
installed: '0.0.0',
49+
latest: '0.0.0',
50+
},
51+
creationDate: '2025-08-06 15:03:00',
52+
plan: 'XS',
53+
// Remove encryption since it's not part of the addon features
54+
features: [
55+
{
56+
code: 'cpu',
57+
type: 'number',
58+
value: 2,
59+
},
60+
{
61+
code: 'memory',
62+
type: 'bytes',
63+
value: 4,
64+
},
65+
{
66+
code: 'disk-size',
67+
type: 'bytes',
68+
value: 40,
69+
},
70+
{
71+
code: 'encryption-at-rest',
72+
type: 'boolean',
73+
value: 'false',
74+
},
75+
],
76+
};
77+
78+
updateComponent('state', { type: 'loading', ...LOADING_STATE });
79+
updateComponent('docLink', {
80+
text: i18n('cc-addon-info.doc-link.jenkins'),
81+
href: getDocUrl('/addons/jenkins'),
82+
});
83+
84+
api
85+
.getJenkinsAddonInfo()
86+
.then(({ rawAddon, addonProvider }) => {
87+
// Get standard features from plan
88+
const features = formatAddonFeatures(rawAddon.plan.features, ['cpu', 'memory', 'disk-size']);
89+
90+
// Add encryption feature from addonProvider
91+
const encryptionFeature = addonProvider.features.find((f) => f.name === 'encryption');
92+
if (encryptionFeature) {
93+
features.push({
94+
code: 'encryption-at-rest',
95+
type: 'boolean',
96+
value: `encryptionFeature.enabled`,
97+
});
98+
}
99+
100+
updateComponent('state', {
101+
type: 'loaded',
102+
version: {
103+
stateType: 'up-to-date',
104+
installed: addonProvider.version,
105+
latest: addonProvider.version,
106+
},
107+
creationDate: rawAddon.creationDate,
108+
plan: rawAddon.plan.name,
109+
features,
110+
});
111+
})
112+
.catch((error) => {
113+
console.error(error);
114+
updateComponent('state', { type: 'error' });
115+
});
116+
},
117+
});
118+
119+
class Api extends CcAddonInfoClient {
120+
/**
121+
* @param {Object} config - Configuration object
122+
* @param {ApiConfig} config.apiConfig - API configuration
123+
* @param {string} config.ownerId - Owner identifier
124+
* @param {string} config.addonId - Addon identifier
125+
* @param {{ base: string, console: string }} [config.grafanaLink] - Base url to build a grafana link to the app
126+
* @param {AbortSignal} config.signal - Signal to abort calls
127+
*/
128+
constructor({ apiConfig, ownerId, addonId, grafanaLink, signal }) {
129+
super({ apiConfig, ownerId, addonId, providerId: PROVIDER_ID, grafanaLink, signal });
130+
}
131+
132+
/**
133+
*
134+
* @param {string} providerId
135+
* @returns {Promise<JenkinsProviderInfo>}
136+
*/
137+
_getAddonProvider(providerId) {
138+
return getAddonProvider({ providerId, addonId: this._addonId }).then(
139+
sendToApi({ apiConfig: this._apiConfig, signal: this._signal, cacheDelay: ONE_SECOND }),
140+
);
141+
}
142+
143+
/**
144+
* @returns {Promise<{ rawAddon: RawAddon, addonProvider: JenkinsProviderInfo }>}
145+
*/
146+
async getJenkinsAddonInfo() {
147+
const rawAddon = await this._getAddon();
148+
const addonProvider = await this._getAddonProvider(rawAddon.provider.id);
149+
150+
return { rawAddon, addonProvider };
151+
}
152+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
---
2+
kind: '🛠 Addon/<cc-addon-info>'
3+
title: '💡 Smart (Jenkins)'
4+
---
5+
# 💡 Smart `<cc-addon-info smart-mode="jenkins">`
6+
7+
## ℹ️ Details
8+
9+
<table>
10+
<tr><td><strong>Component </strong> <td><a href="🛠-addons-cc-addon-info--default-story"><code>&lt;cc-addon-info&gt;</code></a>
11+
<tr><td><strong>Selector </strong> <td><code>cc-addon-info[smart-mode="jenkins"]</code>
12+
<tr><td><strong>Requires auth</strong> <td>Yes
13+
</table>
14+
15+
## ⚙️ Params
16+
17+
| Name | Type | Details | Default |
18+
| ----------- | ----------- |--------------------------------------------------------| ------- |
19+
| `apiConfig` | `ApiConfig` | Object with API configuration (target host, tokens...) | |
20+
| `ownerId` | `string` | UUID prefixed with orga_ | |
21+
| `addonId` | `string` | ID of the add-on | |
22+
23+
```ts
24+
interface ApiConfig {
25+
API_HOST: string;
26+
API_OAUTH_TOKEN: string;
27+
API_OAUTH_TOKEN_SECRET: string;
28+
OAUTH_CONSUMER_KEY: string;
29+
OAUTH_CONSUMER_SECRET: string;
30+
}
31+
```
32+
33+
## 🌐 API endpoints
34+
35+
| Method | URL | Cache? |
36+
|--------|-------------------------------------------------------|------------|
37+
| `GET` | `/v2/organisations/${ownerId}/addons/${addonId}` | 1 second |
38+
| `GET` | `/v2/providers/jenkins/addons/${addonId}` | 1 second |
39+
40+
41+
## ⬇️️ Examples
42+
43+
```html
44+
<cc-smart-container context='{
45+
"apiConfig": {
46+
"API_HOST": "",
47+
"API_OAUTH_TOKEN": "",
48+
"API_OAUTH_TOKEN_SECRET": "",
49+
"OAUTH_CONSUMER_KEY": "",
50+
"OAUTH_CONSUMER_SECRET": ""
51+
},
52+
"ownerId": "orga_XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
53+
"addonId": "addon_XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
54+
}'>
55+
<cc-addon-info smart-mode="jenkins"></cc-addon-info>
56+
</cc-smart-container>
57+
```

src/components/cc-addon-info/cc-addon-info.types.d.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,23 @@ export interface AddonVersionInfo {
127127
latest: string;
128128
needUpdate: boolean;
129129
}
130+
131+
export interface JenkinsProviderInfo {
132+
id: string;
133+
app_id: string;
134+
owner_id: string;
135+
plan: string;
136+
zone: string;
137+
creation_date: string;
138+
status: string;
139+
host: string;
140+
user: string;
141+
password: string;
142+
version: string;
143+
features: [
144+
{
145+
name: string;
146+
enabled: boolean;
147+
},
148+
];
149+
}

src/translations/translations.en.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ export const translations = {
304304
'cc-addon-info.creation-date.human-friendly-date': /** @param {{ date: string | number }} _ */ ({ date }) =>
305305
formatDatetime(date),
306306
'cc-addon-info.doc-link.elastic': `Elastic Stack - Documentation`,
307+
'cc-addon-info.doc-link.jenkins': `Jenkins - Documentation`,
307308
'cc-addon-info.doc-link.keycloak': `Keycloak - Documentation`,
308309
'cc-addon-info.doc-link.kubernetes': `Kubernetes - Documentation`,
309310
'cc-addon-info.doc-link.matomo': `Matomo - Documentation`,

src/translations/translations.fr.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ export const translations = {
315315
'cc-addon-info.creation-date.human-friendly-date': /** @param {{ date: string | number }} _ */ ({ date }) =>
316316
formatDatetime(date),
317317
'cc-addon-info.doc-link.elastic': `Elastic Stack - Documentation`,
318+
'cc-addon-info.doc-link.jenkins': `Jenkins - Documentation`,
318319
'cc-addon-info.doc-link.keycloak': `Keycloak - Documentation`,
319320
'cc-addon-info.doc-link.kubernetes': `Kubernetes - Documentation`,
320321
'cc-addon-info.doc-link.matomo': `Matomo - Documentation`,

0 commit comments

Comments
 (0)