Skip to content

Commit

Permalink
Merge pull request #51 from hlxsites/api-definition-extensions
Browse files Browse the repository at this point in the history
Api definition extensions
  • Loading branch information
nc-andreashaller authored Oct 18, 2024
2 parents 7fb24fb + 4622fd2 commit e66c545
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 40 deletions.
19 changes: 19 additions & 0 deletions blocks/swaggerui/swaggerui.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
raqn-swaggerui .topbar {
display: none;
}

raqn-swaggerui .swagger-ui-selection ul input {
transition: opacity 0.5s ease;
margin: auto 10px;
}

raqn-swaggerui .swagger-ui-selection ul li.closed input {
opacity: 0;
}

raqn-swaggerui .swagger-ui-selection ul ul {
max-height: 300px;
overflow-y: scroll;
transition: max-height 0.5s ease-out, opacity 0.5s ease-out;
}

raqn-swaggerui .swagger-ui-selection ul li.closed ul {
height: 0;
}
135 changes: 95 additions & 40 deletions blocks/swaggerui/swaggerui.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,57 +4,112 @@ const prefixPath = '/api-definitions';

export default class SwaggerUI extends ComponentBase {

async loadEnvironments() {
const response = await fetch(`${prefixPath}/environments.json`);
return response.json();
}

async loadAPIs() {
const environmentsElement = this.querySelector('.swagger-ui-selection .environments');
const definitionsElement = this.querySelector('.swagger-ui-selection .definitions');
switchAPI(hash) {
const currentEnvironment = hash.length > 0 ? hash.substring(1).replace(/--.+$/, '') : false;
this.querySelectorAll('.swagger-ui-selection > ul > li').forEach((item) => {
if(item.dataset.environment === currentEnvironment) {
item.classList.remove('closed');
} else {
item.classList.add('closed');
}
});
const currentAPI = currentEnvironment && (() => {
const index = hash.indexOf('--');
return index !== -1 ? hash.substring(index + 2) : false;
})();

const wrapperElement = this.querySelector('.swagger-ui-wrapper');
wrapperElement.innerHTML = '';
if(currentAPI) {
window.SwaggerUIBundle({
url: `${prefixPath}/${currentEnvironment}/${currentAPI}.yaml`,
domNode: wrapperElement,
presets: [window.SwaggerUIBundle.presets.apis, window.SwaggerUIStandalonePreset],
layout: 'StandaloneLayout',
});
}
}

const environments = await this.loadEnvironments();
environments.forEach((environment) => {
const option = document.createElement('option');
option.value = environment;
option.textContent = environment;
environmentsElement.appendChild(option);
});
navigationClick(e, hash) {
e.preventDefault();
if(!window.location.hash.startsWith(hash)) {
window.location.hash = hash;
this.switchAPI(hash);
}
}

environmentsElement.addEventListener('change', async () => {
const response = await fetch(`${prefixPath}/${environmentsElement.value}/index.json`);
const apis = await response.json();
definitionsElement.innerHTML = '';
wrapperElement.innerHTML = '';
apis.forEach((api) => {
const option = document.createElement('option');
option.value = api;
option.textContent = api;
definitionsElement.appendChild(option);
async generateAPISelection(selectionElement) {
const response = await fetch(`${prefixPath}/environments.json`);
const environments = await response.json();
const environmentElements = await Promise.all(environments.map(async (environment) => {
const item = document.createElement('li');
item.dataset.environment = environment.folder;
const anchor = document.createElement('a');
const url = new URL(window.location.href);
url.hash = environment.folder;
anchor.addEventListener('click', (e) => this.navigationClick(e, url.hash));
anchor.href = url.toString();
anchor.textContent = environment.label;
item.appendChild(anchor);
const filter = document.createElement('input');
filter.placeholder = 'Search';
item.appendChild(filter);
const apiResponse = await fetch(`${prefixPath}/${environment.folder}/index.json`);
const apis = await apiResponse.json();
const definitionsElement = document.createElement('ul');
apis.sort((a, b) => a.label.localeCompare(b.label)).forEach((api) => {
const apiItem = document.createElement('li');
const apiAnchor = document.createElement('a');
const apiUrl = new URL(window.location.href);
apiUrl.hash = `${environment.folder}--${api.id}`;
apiAnchor.addEventListener('click', (e) => this.navigationClick(e, apiUrl.hash));
apiAnchor.href = apiUrl.toString();
apiAnchor.textContent = `${api.label}${api.version ? ` (${api.version})` : ''}`;
apiItem.appendChild(apiAnchor);
definitionsElement.appendChild(apiItem);
});
definitionsElement.addEventListener('change', () => {
const file = definitionsElement.value;
wrapperElement.innerHTML = '';
window.SwaggerUIBundle({
url: `${prefixPath}/${environmentsElement.value}/${file}`,
domNode: wrapperElement,
presets: [window.SwaggerUIBundle.presets.apis, window.SwaggerUIStandalonePreset],
layout: 'StandaloneLayout',
item.appendChild(definitionsElement);
filter.addEventListener('input', () => {
definitionsElement.querySelectorAll('li').forEach((apiItem) => {
if (apiItem.textContent.toLowerCase().includes(filter.value.toLowerCase())) {
apiItem.style.display = 'block';
} else {
apiItem.style.display = 'none';
}
});
});
definitionsElement.dispatchEvent(new Event('change'));
return item;
}));
const environmentsElement = selectionElement.querySelector(':scope > ul');
environmentElements.forEach((option) => environmentsElement.appendChild(option));
}

async loadAPIs(apiFilter) {
const selectionElement = this.querySelector('.swagger-ui-selection');
if(apiFilter.length === 0) {
await this.generateAPISelection(selectionElement);
}

const hashes = apiFilter.length > 0 ? apiFilter : [window.location.hash];
hashes.forEach((hash) => {
const wrapper = document.createElement('div');
wrapper.classList.add('swagger-ui-wrapper');
this.insertBefore(wrapper, selectionElement.nextSibling);
this.switchAPI(hash);
});
environmentsElement.dispatchEvent(new Event('change'));

this.switchAPI(apiFilter.length > 0 ? apiFilter[0] : window.location.hash);
}

async ready() {
const apiFilter = [...this.querySelectorAll('a')]
.map((a) => new URL(a.href).hash)
.filter((hash) => hash.length > 0 && hash.indexOf('--') > 0);

this.innerHTML = `
<div class="swagger-ui-selection">
<select class="environments"></select>
<select class="definitions"></select>
</div>
<div class="swagger-ui-wrapper"></div>`;
<ul></ul>
</div>`;

const loadCSS = async (href) => new Promise((resolve, reject) => {
const link = document.createElement('link');
Expand All @@ -77,7 +132,7 @@ export default class SwaggerUI extends ComponentBase {
loadJS('/blocks/swaggerui/libs/swagger-ui-standalone-preset.js'),
]);

await this.loadAPIs();
await this.loadAPIs(apiFilter);
}

}

0 comments on commit e66c545

Please sign in to comment.