Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 57 additions & 2 deletions demo-smart/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,21 @@
cc-addon-info.smart-kubernetes
</a>
</li>
<li>
<a class="definition-link" href="?definition=cc-addon-header.smart-elastic&smart-mode=elastic"
>cc-addon-header.smart-elastic</a
>
</li>
<li>
<a class="definition-link" href="?definition=cc-addon-info.smart-elastic&smart-mode=elastic"
>cc-addon-info.smart-elastic</a
>
</li>
<li>
<a class="definition-link" href="?definition=cc-addon-credentials-beta.smart-elastic&smart-mode=elastic"
>cc-addon-credentials-beta.smart-elastic</a
>
</li>
</ul>

<div class="context-buttons">
Expand Down Expand Up @@ -250,10 +265,50 @@
ACME FOO
</button>
<button
data-context='{"ownerId":"orga_3547a882-d464-4c34-8168-add4b3e0c135","addonId":"addon_e41d1602-9ec0-43ce-811a-1f47efc2c962"}'
data-context='{
"ownerId":"orga_3547a882-d464-4c34-8168-add4b3e0c135",
"addonId":"addon_e41d1602-9ec0-43ce-811a-1f47efc2c962",
"logsUrlPattern":"/organisations/orga_3547a882-d464-4c34-8168-add4b3e0c135/applications/:id/logs",
"scalabilityUrlPattern": "/organisations/orga_3547a882-d464-4c34-8168-add4b3e0c135/applications/:id/settings",
"grafanaLink": {
"base": "https://grafana.services.clever-cloud.com",
"console": "https://console.clever-cloud.com"
},
"appOverviewUrlPattern": "/organisations/orga_3547a882-d464-4c34-8168-add4b3e0c135/applications/:id"
}'
>
addon-elastic
</button>
<button
data-context='{
"ownerId":"orga_3547a882-d464-4c34-8168-add4b3e0c135",
"addonId":"addon_1efdc7b6-234b-4517-9402-3413a2968229",
"logsUrlPattern":"/organisations/orga_3547a882-d464-4c34-8168-add4b3e0c135/applications/:id/logs",
"scalabilityUrlPattern": "/organisations/orga_3547a882-d464-4c34-8168-add4b3e0c135/applications/:id/settings",
"grafanaLink": {
"base": "https://grafana.services.clever-cloud.com",
"console": "https://console.clever-cloud.com"
},
"appOverviewUrlPattern": "/organisations/orga_3547a882-d464-4c34-8168-add4b3e0c135/applications/:id"
}'
>
addon-elastic-kibana
</button>
<button
data-context='{
"ownerId":"orga_3547a882-d464-4c34-8168-add4b3e0c135",
"addonId":"addon_ce389853-4632-4508-aaa1-cd6ae287046c",
"logsUrlPattern":"/organisations/orga_3547a882-d464-4c34-8168-add4b3e0c135/addons/:id/logs",
"scalabilityUrlPattern": "/organisations/orga_3547a882-d464-4c34-8168-add4b3e0c135/applications/:id/settings",
"grafanaLink": {
"base": "https://grafana.services.clever-cloud.com",
"console": "https://console.clever-cloud.com"
},
"appOverviewUrlPattern": "/organisations/orga_3547a882-d464-4c34-8168-add4b3e0c135/applications/:id"
}'
>
addon-elastic-alone
</button>
<button
data-context='{"ownerId":"orga_3547a882-d464-4c34-8168-add4b3e0c135","addonId":"addon_1eef66a7-6840-4050-a484-2f7dc14dfded"}'
>
Expand Down Expand Up @@ -299,7 +354,7 @@
"console": "https://console.clever-cloud.com"
},
"appOverviewUrlPattern": "/organisations/orga_3547a882-d464-4c34-8168-add4b3e0c135/applications/:id",
"addonDashboardUrlPattern": "/organisations/orga_3547a882-d464-4c34-8168-addons/:id"
"addonDashboardUrlPattern": "/organisations/orga_3547a882-d464-4c34-8168-add4b3e0c135/addons/:id"
}'
>
addon-keycloak
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
// @ts-expect-error FIXME: remove when clever-client exports types
import { getAddon as getAddonProvider } from '@clevercloud/client/esm/api/v2/providers.js';
// @ts-expect-error FIXME: remove when clever-client exports types
import { ONE_SECOND } from '@clevercloud/client/esm/with-cache.js';
import { getDocUrl } from '../../lib/dev-hub-url.js';
import { sendToApi } from '../../lib/send-to-api.js';
import { defineSmartComponent } from '../../lib/smart/define-smart-component.js';
import { i18n } from '../../translations/translation.js';
import '../cc-smart-container/cc-smart-container.js';
import { CcAddonCredentialsBetaClient } from './cc-addon-credentials-beta.client.js';
import './cc-addon-credentials-beta.js';

/** @type {AddonCredentialsBetaStateLoading} */
const LOADING_STATE = {
type: 'loading',
tabs: {
elastic: {
content: [
{
code: 'host',
value: 'fake-skeleton',
},
{
code: 'user',
value: 'fake-skeleton',
},
{
code: 'password',
value: 'fake-skeleton',
},
],
docLink: {
text: i18n('cc-addon-credentials-beta.doc-link.elastic'),
href: getDocUrl('/addons/elastic'),
},
},
kibana: {
content: [
{
code: 'user',
value: 'fake-skeleton',
},
{
code: 'password',
value: 'fake-skeleton',
},
],
docLink: {
text: i18n('cc-addon-credentials-beta.doc-link.elastic-kibana'),
href: getDocUrl('/addons/elastic/#kibana'),
},
},
apm: {
content: [
{
code: 'user',
value: 'fake-skeleton',
},
{
code: 'password',
value: 'fake-skeleton',
},
{
code: 'token',
value: 'fake-skeleton',
},
],
docLink: {
text: i18n('cc-addon-credentials-beta.doc-link.elastic-apm'),
href: getDocUrl('/addons/elastic/#elastic-apm'),
},
},
},
};
const PROVIDER_ID = 'es-addon';

/**
* @typedef {import('./cc-addon-credentials-beta.js').CcAddonCredentialsBeta} CcAddonCredentialsBeta
* @typedef {import('./cc-addon-credentials-beta.types.js').AddonCredentialsBetaStateLoaded} AddonCredentialsBetaStateLoaded
* @typedef {import('./cc-addon-credentials-beta.types.js').AddonCredentialsBetaStateLoading} AddonCredentialsBetaStateLoading
* @typedef {import('./cc-addon-credentials-beta.types.js').ElasticProviderInfo} ElasticProviderInfo
* @typedef {import('../cc-addon-credentials-content/cc-addon-credentials-content.types.js').AddonCredential} AddonCredential
* @typedef {import('../../lib/send-to-api.js').ApiConfig} ApiConfig
* @typedef {import('../../lib/smart/smart-component.types.js').OnContextUpdateArgs<CcAddonCredentialsBeta>} OnContextUpdateArgs
*/

defineSmartComponent({
selector: 'cc-addon-credentials-beta[smart-mode="elastic"]',
params: {
apiConfig: { type: Object },
addonId: { type: String },
ownerId: { type: String },
},
/**
* @param {OnContextUpdateArgs} args
*/
onContextUpdate({ context, updateComponent, signal }) {
const { apiConfig, addonId, ownerId } = context;
const api = new Api({ apiConfig, ownerId, addonId, signal });

updateComponent('state', LOADING_STATE);

api
.getAllCredentials()
.then(({ elastic, kibana, apm }) => {
updateComponent(
'state',
/** @param {AddonCredentialsBetaStateLoaded|AddonCredentialsBetaStateLoading} state */
(state) => {
state.type = 'loaded';
// Build tabs object with only enabled services
/** @type {Record<string, {content: AddonCredential[], docLink: {text: string, href: string}}>} */
const updatedTabs = {
elastic: {
...state.tabs.elastic,
content: elastic,
},
};

if (kibana != null) {
updatedTabs.kibana = {
...state.tabs.kibana,
content: kibana,
};
}

if (apm != null) {
updatedTabs.apm = {
...state.tabs.apm,
content: apm,
};
}

state.tabs = updatedTabs;
},
);
})
.catch((error) => {
console.error(error);
updateComponent('state', { type: 'error' });
});
},
});

class Api extends CcAddonCredentialsBetaClient {
/**
* @param {object} params
* @param {ApiConfig} params.apiConfig
* @param {string} params.ownerId
* @param {string} params.addonId
* @param {AbortSignal} params.signal
*/
constructor({ apiConfig, ownerId, addonId, signal }) {
super({ apiConfig, ownerId, addonId, providerId: PROVIDER_ID, signal });
}

/**
*
* @param {string} providerId
* @returns {Promise<ElasticProviderInfo>}
*/
_getAddonProvider(providerId) {
return getAddonProvider({ providerId, addonId: this._addonId }).then(
sendToApi({ apiConfig: this._apiConfig, signal: this._signal, cacheDelay: ONE_SECOND }),
);
}

/**
* @param {'elastic' | 'kibana' | 'apm'} tabType
* @return {Promise<AddonCredential[]>}
*/
async getCredentials(tabType) {
const addonProvider = await this._getAddonProvider(this._providerId);
switch (tabType) {
case 'elastic':
return [
{
code: 'host',
value: addonProvider.config.host,
},
{
code: 'user',
value: addonProvider.config.user,
},
{
code: 'password',
value: addonProvider.config.password,
},
];
case 'kibana':
return [
{
code: 'user',
value: addonProvider.config.kibana_user,
},
{
code: 'password',
value: addonProvider.config.kibana_password,
},
];
case 'apm':
return [
{
code: 'user',
value: addonProvider.config.apm_user,
},
{
code: 'password',
value: addonProvider.config.apm_password,
},
{
code: 'token',
value: addonProvider.config.apm_auth_token,
},
];
}
}

/**
* @return {Promise<{elastic: AddonCredential[], kibana: AddonCredential[] | null, apm: AddonCredential[] | null}>}
*/
async getAllCredentials() {
const addonProvider = await this._getAddonProvider(this._providerId);

// Check which services are enabled
const kibanaService = addonProvider.services.find((service) => service.name === 'kibana');
const apmService = addonProvider.services.find((service) => service.name === 'apm');
const isKibanaEnabled = kibanaService?.enabled ?? false;
const isApmEnabled = apmService?.enabled ?? false;

const [elasticCredentials, kibanaCredentials, apmCredentials] = await Promise.all([
this.getCredentials('elastic'),
isKibanaEnabled ? this.getCredentials('kibana') : null,
isApmEnabled ? this.getCredentials('apm') : null,
]);

return {
elastic: elasticCredentials,
kibana: kibanaCredentials,
apm: apmCredentials,
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
kind: '🛠 Addon/<cc-addon-credentials-beta>'
title: '💡 Smart (Elastic)'
---
# 💡 Smart `<cc-addon-credentials-beta smart-mode="elastic">`

## ℹ️ Details

<table>
<tr><td><strong>Component </strong> <td><a href="🛠-addon-credentials-beta-cc-addon-credentials-beta--default-story"><code>&lt;cc-addon-credentials-beta&gt;</code></a>
<tr><td><strong>Selector </strong> <td><code>cc-addon-credentials-beta[smart-mode="elastic"]</code>
<tr><td><strong>Requires auth</strong> <td>Yes
</table>

## ⚙️ Params

| Name | Type | Details | Default |
|-------------|-------------|--------------------------------------------------------|---------|
| `apiConfig` | `ApiConfig` | Object with API configuration (target host, tokens...) | |
| `addonId` | `string` | UUID of the addon | |
| `ownerId` | `string` | UUID of the owner (organisation or user) | |

```ts
interface ApiConfig {
API_HOST: string,
API_OAUTH_TOKEN: string,
API_OAUTH_TOKEN_SECRET: string,
OAUTH_CONSUMER_KEY: string,
OAUTH_CONSUMER_SECRET: string,
}
```

## 🌐 API endpoints

| Method | URL | Cache? |
|----------|--------------------------------------------------------|------------|
| `GET` | `/v2/providers/es-addon/${addonId}` | 1 second |

## ⬇️️ Examples

```html
<cc-smart-container context='{
"apiConfig": {
API_HOST: "",
API_OAUTH_TOKEN: "",
API_OAUTH_TOKEN_SECRET: "",
OAUTH_CONSUMER_KEY: "",
OAUTH_CONSUMER_SECRET: "",
},
"addonId": "addon_xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"ownerId": "orga_xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}'>
<cc-addon-credentials-beta smart-mode="elastic"></cc-addon-credentials-beta>
</cc-smart-container>
```
Loading