Skip to content

Commit

Permalink
move swagger ui navigation to separate block
Browse files Browse the repository at this point in the history
  • Loading branch information
nc-andreashaller committed Dec 19, 2024
1 parent 252f684 commit cd8d633
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 92 deletions.
19 changes: 0 additions & 19 deletions blocks/swaggerui/swaggerui.css
Original file line number Diff line number Diff line change
@@ -1,22 +1,3 @@
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;
}
81 changes: 8 additions & 73 deletions blocks/swaggerui/swaggerui.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
import ComponentBase from '../../scripts/component-base.js';

const prefixPath = '/api-definitions';
export const prefixPath = '/api-definitions';
export const apiSwitchEvent = 'swaggerUI:apiSwitch';

export default class SwaggerUI extends ComponentBase {

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;
Expand All @@ -30,71 +24,12 @@ export default class SwaggerUI extends ComponentBase {
}
}

navigationClick(e, hash) {
e.preventDefault();
if(!window.location.hash.startsWith(hash)) {
window.location.hash = hash;
this.switchAPI(hash);
}
}

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);
});
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';
}
});
});
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.append(wrapper);
this.switchAPI(hash);
});

Expand All @@ -103,15 +38,15 @@ export default class SwaggerUI extends ComponentBase {

async init() {
super.init();

document.addEventListener(apiSwitchEvent, (e) => this.switchAPI(e.detail.hash));

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">
<ul></ul>
</div>`;

this.innerHTML = '';

const loadCSS = async (href) => new Promise((resolve, reject) => {
const link = document.createElement('link');
link.rel = 'stylesheet';
Expand Down
14 changes: 14 additions & 0 deletions blocks/swaggeruinavigation/swaggeruinavigation.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
raqn-swaggerui-navigation > input {
margin: auto 10px;
}

raqn-swaggerui-navigation > ul {
height: calc(100vh - var(--header-height, 110px) - 250px);
overflow-y: auto;
}

raqn-swaggerui-navigation > ul.closed {
height: 0;
padding: 0;
margin: 0;
}
82 changes: 82 additions & 0 deletions blocks/swaggeruinavigation/swaggeruinavigation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import ComponentBase from '../../scripts/component-base.js';
import { prefixPath, apiSwitchEvent } from '../swaggerui/swaggerui.js';

export default class SwaggerUINavigation extends ComponentBase {

navigationClick(e, hash) {
e?.preventDefault();
this.querySelectorAll(':scope > ul[data-environment]').forEach((item) => {
if(hash.startsWith(`#${item.dataset.environment}`)) {
item.classList.remove('closed');
} else if(!item.classList.contains('closed')) {
item.classList.add('closed');
}
});
if(!window.location.hash.startsWith(hash)) {
window.location.hash = hash;
document.dispatchEvent(new CustomEvent(apiSwitchEvent, { detail: { hash } }));
}
}

async generateAPISelection() {
const response = await fetch(`${prefixPath}/environments.json`);
const environments = await response.json();
const environmentOptions = await Promise.all(environments.map(async (environment) => {
const item = document.createElement('option');
item.textContent = environment.label;
item.value = environment.folder;
if(window.location.hash.startsWith(`#${environment.folder}`)) {
item.selected = true;
}

const apiResponse = await fetch(`${prefixPath}/${environment.folder}/index.json`);
const apis = await apiResponse.json();
const definitionsElement = document.createElement('ul');
definitionsElement.dataset.environment = environment.folder;
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);
});
this.appendChild(definitionsElement);
return item;
}));
const environmentsSelect = this.querySelector(':scope > select[name="environment-selection"]');
environmentOptions.forEach((option) => environmentsSelect.appendChild(option));

environmentsSelect.addEventListener('change', (event) => this.navigationClick(event, `#${event.target.value}`));
this.navigationClick(null, `#${environmentsSelect.selectedOptions[0].value}`);
}

async init() {
super.init();

this.innerHTML = `
<label for="environment-selection">Environment:</label>
<select name="environment-selection"></select>
<label for="environment-filter">Filter:</label>
<input name="environment-filter">
`;

await this.generateAPISelection();
const filter = this.querySelector(':scope > input');
const allApis = this.querySelectorAll(':scope > ul[data-environment] > li');
filter.addEventListener('input', () => {
allApis.forEach((apiItem) => {
if (apiItem.textContent.toLowerCase().includes(filter.value.toLowerCase())) {
apiItem.style.display = 'block';
} else {
apiItem.style.display = 'none';
}
});
});

}

}
8 changes: 8 additions & 0 deletions scripts/component-list/component-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,14 @@ export const componentList = {
priority: 4,
},
},
swaggeruinavigation: {
tag: 'raqn-swaggerui-navigation',
method: 'replace',
module: {
path: '/blocks/swaggeruinavigation/swaggeruinavigation',
priority: 2,
},
},
swaggerui: {
tag: 'raqn-swaggerui',
method: 'replace',
Expand Down

0 comments on commit cd8d633

Please sign in to comment.