Skip to content

Commit 0e932c3

Browse files
Merge pull request #1561 from CleverCloud/dashboard-addons/metabase
feat(cc-addon-*): add Metabase
2 parents 2af7b0d + 28cbbb4 commit 0e932c3

File tree

8 files changed

+486
-4
lines changed

8 files changed

+486
-4
lines changed

demo-smart/index.html

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,16 @@
198198
>cc-addon-info.smart-otoroshi</a
199199
>
200200
</li>
201+
<li>
202+
<a class="definition-link" href="?definition=cc-addon-header.smart-metabase&smart-mode=metabase"
203+
>cc-addon-header.smart-metabase</a
204+
>
205+
</li>
206+
<li>
207+
<a class="definition-link" href="?definition=cc-addon-info.smart-metabase&smart-mode=metabase"
208+
>cc-addon-info.smart-metabase</a
209+
>
210+
</li>
201211
</ul>
202212

203213
<div class="context-buttons">
@@ -284,6 +294,22 @@
284294
>
285295
addon-keycloak
286296
</button>
297+
<button
298+
data-context='{
299+
"ownerId":"orga_3547a882-d464-4c34-8168-add4b3e0c135",
300+
"addonId":"addon_e396509c-e59f-44b3-93e5-5d00f04eb5dc",
301+
"logsUrlPattern":"/organisations/orga_3547a882-d464-4c34-8168-add4b3e0c135/applications/:id/logs",
302+
"grafanaLink": {
303+
"base": "https://grafana.services.clever-cloud.com",
304+
"console": "https://console.clever-cloud.com"
305+
},
306+
"appOverviewUrlPattern": "/organisations/orga_3547a882-d464-4c34-8168-add4b3e0c135/applications/:id",
307+
"addonDashboardUrlPattern": "/organisations/orga_3547a882-d464-4c34-8168-add4b3e0c135/addons/:id",
308+
"scalabilityUrlPattern": "/organisations/orga_3547a882-d464-4c34-8168-add4b3e0c135/applications/:id/settings"
309+
}'
310+
>
311+
addon-metabase
312+
</button>
287313
<button
288314
data-context='{
289315
"ownerId":"orga_3547a882-d464-4c34-8168-add4b3e0c135",
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
import { fakeString } from '../../lib/fake-strings.js';
2+
import { notify, notifyError } from '../../lib/notifications.js';
3+
import { defineSmartComponent } from '../../lib/smart/define-smart-component.js';
4+
import { generateDocsHref } from '../../lib/utils.js';
5+
import { i18n } from '../../translations/translation.js';
6+
import '../cc-smart-container/cc-smart-container.js';
7+
import { CcAddonHeaderClient } from './cc-addon-header.client.js';
8+
import './cc-addon-header.js';
9+
10+
const DOCS_URL = generateDocsHref(`/addons/metabase`);
11+
const PROVIDER_ID = 'metabase';
12+
13+
/**
14+
* @typedef {import('./cc-addon-header.js').CcAddonHeader} CcAddonHeader
15+
* @typedef {import('../../lib/smart/smart-component.types.js').OnContextUpdateArgs<CcAddonHeader>} OnContextUpdateArgs
16+
*/
17+
18+
defineSmartComponent({
19+
selector: 'cc-addon-header[smart-mode=metabase]',
20+
params: {
21+
apiConfig: { type: Object },
22+
ownerId: { type: String },
23+
addonId: { type: String },
24+
logsUrlPattern: { type: String },
25+
productStatus: { type: String, optional: true },
26+
},
27+
28+
/** @param {OnContextUpdateArgs} args */
29+
onContextUpdate({ context, updateComponent, onEvent, signal }) {
30+
const { apiConfig, ownerId, addonId, productStatus } = context;
31+
const api = new CcAddonHeaderClient({ apiConfig, ownerId, addonId, providerId: PROVIDER_ID, signal });
32+
let logsUrl = '';
33+
34+
updateComponent('state', {
35+
type: 'loading',
36+
logsUrl: fakeString(15),
37+
openLinks: [
38+
{
39+
url: fakeString(15),
40+
name: fakeString(5),
41+
},
42+
],
43+
actions: {
44+
restart: true,
45+
rebuildAndRestart: true,
46+
},
47+
productStatus: fakeString(4),
48+
});
49+
50+
api
51+
.getAddonWithOperatorAndZone()
52+
.then(({ rawAddon, operator, zone }) => {
53+
const javaAppId = operator.resources.entrypoint;
54+
logsUrl = context.logsUrlPattern.replace(':id', javaAppId);
55+
56+
updateComponent('state', {
57+
type: 'loaded',
58+
providerId: rawAddon.provider.name,
59+
providerLogoUrl: rawAddon.provider.logoUrl,
60+
name: rawAddon.name,
61+
id: rawAddon.realId,
62+
zone,
63+
logsUrl,
64+
openLinks: [
65+
{
66+
name: 'METABASE',
67+
url: operator.accessUrl,
68+
},
69+
],
70+
actions: {
71+
restart: true,
72+
rebuildAndRestart: true,
73+
},
74+
productStatus,
75+
});
76+
})
77+
.catch((error) => {
78+
console.error(error);
79+
updateComponent('state', {
80+
type: 'error',
81+
});
82+
});
83+
84+
onEvent('cc-addon-restart', () => {
85+
updateComponent('state', (state) => {
86+
state.type = 'restarting';
87+
});
88+
89+
api
90+
.restartAddon()
91+
.then(() => {
92+
notify({
93+
intent: 'success',
94+
message: i18n('cc-addon-header.restart.success.message', { logsUrl, docsUrl: DOCS_URL }),
95+
title: i18n('cc-addon-header.restart.success.title'),
96+
options: {
97+
timeout: 0,
98+
closeable: true,
99+
},
100+
});
101+
})
102+
.catch((error) => {
103+
console.error(error);
104+
notifyError(i18n('cc-addon-header.restart.error'));
105+
})
106+
.finally(() => {
107+
updateComponent('state', (state) => {
108+
state.type = 'loaded';
109+
});
110+
});
111+
});
112+
113+
onEvent('cc-addon-rebuild', () => {
114+
updateComponent('state', (state) => {
115+
state.type = 'rebuilding';
116+
});
117+
118+
api
119+
.rebuildAndRestartAddon()
120+
.then(() => {
121+
notify({
122+
intent: 'success',
123+
message: i18n('cc-addon-header.rebuild.success.message', { logsUrl, docsUrl: DOCS_URL }),
124+
title: i18n('cc-addon-header.rebuild.success.title'),
125+
options: {
126+
timeout: 0,
127+
closeable: true,
128+
},
129+
});
130+
})
131+
.catch((error) => {
132+
console.error(error);
133+
notifyError(i18n('cc-addon-header.rebuild.error'));
134+
})
135+
.finally(() => {
136+
updateComponent('state', (state) => {
137+
state.type = 'loaded';
138+
});
139+
});
140+
});
141+
},
142+
});
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
---
2+
kind: '🛠 Addon/<cc-addon-header>'
3+
title: '💡 Smart (Metabase)'
4+
---
5+
# 💡 Smart `<cc-addon-header smart-mode="metabase">`
6+
7+
## ℹ️ Details
8+
9+
<table>
10+
<tr><td><strong>Component </strong> <td><a href="🛠-addons-cc-addon-header--default-story"><code>&lt;cc-addon-header&gt;</code></a>
11+
<tr><td><strong>Selector </strong> <td><code>cc-addon-header[smart-mode="metabase"]</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+
| `logsUrlPattern` | `string` | Pattern for the logs url (Example : `/organisations/${ownerId}/applications/${appId}/logs`) | |
23+
| `productStatus` | `string` | Maturity status of the product | Optional |
24+
25+
26+
```ts
27+
interface ApiConfig {
28+
API_HOST: string,
29+
API_OAUTH_TOKEN: string,
30+
API_OAUTH_TOKEN_SECRET: string,
31+
OAUTH_CONSUMER_KEY: string,
32+
OAUTH_CONSUMER_SECRET: string,
33+
}
34+
```
35+
36+
## 🌐 API endpoints
37+
38+
| Method | URL | Cache? |
39+
|----------|----------------------------------------------------------------|---------|
40+
| `GET` | `/v2/organisations/${ownerId}/addons/${addonId}` | Default |
41+
| `GET` | `/v4/products/zones?ownerId=${ownerId}` | Default |
42+
| `GET` | `/v4/addon-providers/addon-metabase/addons/${realId}` | Default |
43+
| `POST` | `/v4/addon-providers/addon-metabase/addons/${realId}/reboot` | Default |
44+
| `POST` | `/v4/addon-providers/addon-metabase/addons/${realId}/rebuild` | Default |
45+
46+
47+
## ⬇️️ Examples
48+
49+
```html
50+
<cc-smart-container context='{
51+
"apiConfig": {
52+
API_HOST: "",
53+
API_OAUTH_TOKEN: "",
54+
API_OAUTH_TOKEN_SECRET: "",
55+
OAUTH_CONSUMER_KEY: "",
56+
OAUTH_CONSUMER_SECRET: "",
57+
},
58+
"ownerId": "",
59+
"addonId": "",
60+
"logsUrlPattern": "",
61+
"productStatus": "",
62+
}'>
63+
<cc-addon-header smart-mode="metabase"></cc-addon-header>
64+
</cc-smart-container>
65+
```

0 commit comments

Comments
 (0)