Skip to content

Commit 784a332

Browse files
Merge pull request #1587 from CleverCloud/doc-links/allow-overriding-base-url
Doc links: allow overriding the base url
2 parents ce16294 + ac789a8 commit 784a332

File tree

41 files changed

+437
-198
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+437
-198
lines changed

.storybook/manager.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import { addons } from 'storybook/manager-api';
33
// eslint-disable-next-line import-x/extensions
44
import { create } from 'storybook/theming';
5-
import { generateDocsHref } from '../src/lib/utils.js';
5+
import { getDocUrl } from '../src/lib/dev-hub-url.js';
66
import { enhanceStoryName } from '../src/stories/lib/story-names.js';
77

88
// We could create an addon to provide a control that would switch between dark / light
@@ -12,7 +12,7 @@ const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
1212
const cleverTheme = create({
1313
base: isDarkMode ? 'dark' : 'light',
1414
brandTitle: 'Clever Cloud components',
15-
brandUrl: generateDocsHref(),
15+
brandUrl: getDocUrl(),
1616
brandImage: isDarkMode ? 'imgs/logo-clever-dark.svg' : 'imgs/logo-clever-light.svg',
1717
});
1818

docs/contributing/urls.md

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
---
2+
kind: '👋 Contributing'
3+
title: 'Documentation and asset URLs'
4+
---
5+
6+
# Documentation and asset URLs
7+
8+
When working on components, you'll often need to link to documentation, developer hub pages, or static assets. This guide explains how to handle these URLs correctly.
9+
10+
## Documentation URLs
11+
12+
Use `getDocUrl()` to generate URLs for documentation pages on the Clever Cloud developer hub.
13+
14+
### Import the helper
15+
16+
```js
17+
import { getDocUrl } from '../../lib/dev-hub-url.js';
18+
```
19+
20+
<cc-notice intent="info" message="The path to `dev-hub-url.js` is relative to your component's file."></cc-notice>
21+
22+
### Use the helper
23+
24+
```js
25+
const url = getDocUrl('/billing/unified-invoices');
26+
// => 'https://www.clever.cloud/developers/doc/billing/unified-invoices'
27+
28+
// Empty argument defaults to doc root
29+
const url = getDocUrl();
30+
// => 'https://www.clever.cloud/developers/doc'
31+
```
32+
33+
**_🧐 OBSERVATIONS:_**
34+
35+
* Always use a leading slash: `getDocUrl('/path/to/doc')`.
36+
* You can use the helper directly in templates, as a constant, or in translation files.
37+
* The helper preserves query parameters and URL fragments.
38+
39+
### Usage in translation files
40+
41+
You can use `getDocUrl()` in translation files to generate documentation links:
42+
43+
```js
44+
import { getDocUrl } from '../lib/dev-hub-url.js';
45+
46+
export const translations = {
47+
'my-component.doc-link': () => sanitize`
48+
Read more in the <a href="${getDocUrl('/path/to/doc')}">documentation</a>.
49+
`,
50+
};
51+
```
52+
53+
## Developer hub URLs
54+
55+
Use `getDevHubUrl()` to generate URLs for general developer hub pages (not under `/doc/`).
56+
57+
### Import the helper
58+
59+
```js
60+
import { getDevHubUrl } from '../../lib/dev-hub-url.js';
61+
```
62+
63+
### Use the helper
64+
65+
```js
66+
const url = getDevHubUrl('/api/v4');
67+
// => 'https://www.clever.cloud/developers/api/v4'
68+
69+
// Supports fragments and query params
70+
const url = getDevHubUrl('/api/howto/#oauth1');
71+
// => 'https://www.clever.cloud/developers/api/howto/#oauth1'
72+
```
73+
74+
## Asset URLs
75+
76+
Use `getAssetUrl()` to generate URLs for static assets that are not part of the components project.
77+
78+
### Import the helper
79+
80+
```js
81+
import { getAssetUrl } from '../../lib/assets-url.js';
82+
```
83+
84+
### Use the helper
85+
86+
```js
87+
const url = getAssetUrl('/logos/java-jar.svg');
88+
// => 'https://assets.clever-cloud.com/logos/java-jar.svg'
89+
90+
// Preserves query parameters and fragments
91+
const url = getAssetUrl('/images/logo.png?v=2');
92+
// => 'https://assets.clever-cloud.com/images/logo.png?v=2'
93+
```
94+
95+
### Helper functions for common assets
96+
97+
The `remote-assets.js` file provides convenient wrapper functions for frequently used assets:
98+
99+
```js
100+
import { getFlagUrl, getInfraProviderLogoUrl } from '../../lib/remote-assets.js';
101+
102+
// Country flags
103+
const flag = getFlagUrl('fr');
104+
// => 'https://assets.clever-cloud.com/flags/fr.svg'
105+
106+
// Infrastructure provider logos
107+
const logo = getInfraProviderLogoUrl('ovh');
108+
// => 'https://assets.clever-cloud.com/infra/ovh.svg'
109+
```
110+
111+
## Best practices
112+
113+
### Always use the helpers
114+
115+
**DON'T DO THIS:**
116+
117+
```js
118+
// ❌ Hardcoded URLs
119+
const url = 'https://www.clever.cloud/developers/doc/addons/postgresql';
120+
const asset = 'https://assets.clever-cloud.com/logos/java-jar.svg';
121+
```
122+
123+
**DO THIS:**
124+
125+
```js
126+
// ✅ Use the helpers
127+
const url = getDocUrl('/addons/postgresql');
128+
const asset = getAssetUrl('/logos/java-jar.svg');
129+
```
130+
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
---
2+
kind: '🚀 Getting started'
3+
title: 'Customizing base URLs'
4+
---
5+
6+
# Customizing base URLs
7+
8+
By default, Clever Cloud components generate URLs that point to:
9+
* `https://www.clever.cloud/developers` for documentation and developer hub links
10+
* `https://assets.clever-cloud.com` for static assets
11+
12+
You can override these base URLs.
13+
14+
## Customizing the developer hub base URL
15+
16+
Use `setDevHubBaseUrl()` to change the base URL for documentation and developer hub links.
17+
18+
```js
19+
import { setDevHubBaseUrl } from '@clevercloud/components/dist/dev-hub-url.js';
20+
21+
// Set a custom base URL
22+
setDevHubBaseUrl('https://staging.clever-cloud.com/developers');
23+
24+
// Now import components
25+
import '@clevercloud/components/dist/cc-addon-info.js';
26+
```
27+
28+
After this configuration, all documentation links generated by components will use your custom base URL:
29+
30+
* `getDocUrl('/addons/postgresql')``https://staging.clever-cloud.com/developers/doc/addons/postgresql`
31+
* `getDevHubUrl('/api/v4')``https://staging.clever-cloud.com/developers/api/v4`
32+
33+
## Customizing the assets base URL
34+
35+
Use `setAssetsBaseUrl()` to change the base URL for static assets like logos, flags, and icons.
36+
37+
```js
38+
import { setAssetsBaseUrl } from '@clevercloud/components/dist/assets-url.js';
39+
40+
// Set a custom assets URL
41+
setAssetsBaseUrl('https://cdn.example.com');
42+
43+
// Now import components
44+
import '@clevercloud/components/dist/cc-addon-info.js';
45+
```
46+
47+
After this configuration, all asset URLs generated by components will use your custom base URL:
48+
49+
* `getAssetUrl('/logos/java-jar.svg')``https://cdn.example.com/logos/java-jar.svg`
50+
* `getFlagUrl('fr')``https://cdn.example.com/flags/fr.svg`
51+
52+
## Important: call before importing components
53+
54+
You **must** call `setDevHubBaseUrl()` and `setAssetsBaseUrl()` **before** importing any components. Otherwise, some URLs may still use the default base URLs.
55+
56+
```js
57+
import { setDevHubBaseUrl } from '@clevercloud/components/dist/dev-hub-url.js';
58+
import { setAssetsBaseUrl } from '@clevercloud/components/dist/assets-url.js';
59+
60+
// Configure base URLs first
61+
setDevHubBaseUrl('https://staging.clever-cloud.com/developers');
62+
setAssetsBaseUrl('https://cdn.example.com');
63+
64+
// Then import components
65+
import '@clevercloud/components/dist/cc-addon-info.js';
66+
import '@clevercloud/components/dist/cc-invoice-list.js';
67+
```
68+

src/components/cc-addon-credentials-beta/cc-addon-credentials-beta.smart-keycloak.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
import { getDocUrl } from '../../lib/dev-hub-url.js';
12
import { notifyError, notifySuccess } from '../../lib/notifications.js';
23
import { defineSmartComponent } from '../../lib/smart/define-smart-component.js';
3-
import { generateDocsHref } from '../../lib/utils.js';
44
import { i18n } from '../../translations/translation.js';
55
import '../cc-smart-container/cc-smart-container.js';
66
import { CcAddonCredentialsBetaClient } from './cc-addon-credentials-beta.client.js';
@@ -30,7 +30,7 @@ const LOADING_STATE = {
3030
],
3131
docLink: {
3232
text: i18n('cc-addon-credentials-beta.doc-link.keycloak'),
33-
href: generateDocsHref('/addons/keycloak/#secured-multi-instances'),
33+
href: getDocUrl('/addons/keycloak/#secured-multi-instances'),
3434
},
3535
},
3636
},

src/components/cc-addon-credentials-beta/cc-addon-credentials-beta.smart-otoroshi.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1+
import { getDocUrl } from '../../lib/dev-hub-url.js';
12
import { fakeString } from '../../lib/fake-strings.js';
23
import { notifyError, notifySuccess } from '../../lib/notifications.js';
34
import { defineSmartComponent } from '../../lib/smart/define-smart-component.js';
4-
import { generateDocsHref } from '../../lib/utils.js';
55
import { i18n } from '../../translations/translation.js';
66
import '../cc-smart-container/cc-smart-container.js';
77
import { CcAddonCredentialsBetaClient } from './cc-addon-credentials-beta.client.js';
@@ -29,7 +29,7 @@ const LOADING_STATE = {
2929
],
3030
docLink: {
3131
text: i18n('cc-addon-credentials-beta.doc-link.otoroshi-ng'),
32-
href: generateDocsHref('/addons/otoroshi/#use-otoroshi-in-a-network-group'),
32+
href: getDocUrl('/addons/otoroshi/#use-otoroshi-in-a-network-group'),
3333
},
3434
},
3535
api: {
@@ -58,7 +58,7 @@ const LOADING_STATE = {
5858
],
5959
docLink: {
6060
text: i18n('cc-addon-credentials-beta.doc-link.otoroshi-api'),
61-
href: generateDocsHref('/addons/otoroshi/#manage-otoroshi-from-its-api'),
61+
href: getDocUrl('/addons/otoroshi/#manage-otoroshi-from-its-api'),
6262
},
6363
},
6464
},

src/components/cc-addon-header/cc-addon-header.smart-keycloak.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1+
import { getDocUrl } from '../../lib/dev-hub-url.js';
12
import { fakeString } from '../../lib/fake-strings.js';
23
import { notify, notifyError } from '../../lib/notifications.js';
34
import { defineSmartComponent } from '../../lib/smart/define-smart-component.js';
4-
import { generateDocsHref } from '../../lib/utils.js';
55
import { i18n } from '../../translations/translation.js';
66
import '../cc-smart-container/cc-smart-container.js';
77
import { CcAddonHeaderClient } from './cc-addon-header.client.js';
88
import './cc-addon-header.js';
99

10-
const DOCS_URL = generateDocsHref(`/addons/keycloak`);
10+
const DOCS_URL = getDocUrl(`/addons/keycloak`);
1111
const PROVIDER_ID = 'keycloak';
1212

1313
/**

src/components/cc-addon-header/cc-addon-header.smart-matomo.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1+
import { getDocUrl } from '../../lib/dev-hub-url.js';
12
import { fakeString } from '../../lib/fake-strings.js';
23
import { notify, notifyError } from '../../lib/notifications.js';
34
import { defineSmartComponent } from '../../lib/smart/define-smart-component.js';
4-
import { generateDocsHref } from '../../lib/utils.js';
55
import { i18n } from '../../translations/translation.js';
66
import '../cc-smart-container/cc-smart-container.js';
77
import { CcAddonHeaderClient } from './cc-addon-header.client.js';
88
import './cc-addon-header.js';
99

10-
const DOCS_URL = generateDocsHref(`/addons/matomo`);
10+
const DOCS_URL = getDocUrl(`/addons/matomo`);
1111
const PROVIDER_ID = 'matomo';
1212

1313
/**

src/components/cc-addon-header/cc-addon-header.smart-metabase.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1+
import { getDocUrl } from '../../lib/dev-hub-url.js';
12
import { fakeString } from '../../lib/fake-strings.js';
23
import { notify, notifyError } from '../../lib/notifications.js';
34
import { defineSmartComponent } from '../../lib/smart/define-smart-component.js';
4-
import { generateDocsHref } from '../../lib/utils.js';
55
import { i18n } from '../../translations/translation.js';
66
import '../cc-smart-container/cc-smart-container.js';
77
import { CcAddonHeaderClient } from './cc-addon-header.client.js';
88
import './cc-addon-header.js';
99

10-
const DOCS_URL = generateDocsHref(`/addons/metabase`);
10+
const DOCS_URL = getDocUrl(`/addons/metabase`);
1111
const PROVIDER_ID = 'metabase';
1212

1313
/**

src/components/cc-addon-header/cc-addon-header.smart-otoroshi.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1+
import { getDocUrl } from '../../lib/dev-hub-url.js';
12
import { fakeString } from '../../lib/fake-strings.js';
23
import { notify, notifyError } from '../../lib/notifications.js';
34
import { defineSmartComponent } from '../../lib/smart/define-smart-component.js';
4-
import { generateDocsHref } from '../../lib/utils.js';
55
import { i18n } from '../../translations/translation.js';
66
import '../cc-smart-container/cc-smart-container.js';
77
import { CcAddonHeaderClient } from './cc-addon-header.client.js';
88
import './cc-addon-header.js';
99

10-
const DOCS_URL = generateDocsHref(`/addons/otoroshi`);
10+
const DOCS_URL = getDocUrl(`/addons/otoroshi`);
1111
const PROVIDER_ID = 'otoroshi';
1212

1313
/**

src/components/cc-addon-info/cc-addon-info.client.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import { get as getAddon } from '@clevercloud/client/esm/api/v2/addon.js';
44
import { getGrafanaOrganisation } from '@clevercloud/client/esm/api/v4/saas.js';
55
// @ts-expect-error FIXME: remove when clever-client exports types
66
import { ONE_SECOND } from '@clevercloud/client/esm/with-cache.js';
7+
import { getDevHubUrl } from '../../lib/dev-hub-url.js';
78
import { sendToApi } from '../../lib/send-to-api.js';
8-
import { generateDevHubHref } from '../../lib/utils.js';
99

1010
/**
1111
* @typedef {import('./cc-addon-info.types.js').AddonInfoStateLoaded} AddonInfoStateLoaded
@@ -178,7 +178,7 @@ export function formatVersionState(operatorVersionInfo) {
178178
installed: operatorVersionInfo.installed,
179179
available: operatorVersionInfo.available.filter((version) => version !== operatorVersionInfo.installed),
180180
latest: operatorVersionInfo.latest,
181-
changelogLink: `${generateDevHubHref('/changelog')}`,
181+
changelogLink: `${getDevHubUrl('/changelog')}`,
182182
};
183183
}
184184

0 commit comments

Comments
 (0)