Skip to content

Commit

Permalink
Add links to schema type in schema tables.
Browse files Browse the repository at this point in the history
  • Loading branch information
wparad committed Jan 11, 2024
1 parent 601a29f commit c87337f
Show file tree
Hide file tree
Showing 9 changed files with 53 additions and 18 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ This package follows standard semvar, `<major>.<minor>.<build>`. No breaking cha
* Add `path` and `query` parameters into request interceptor.
* Fix display text for the basic auth type.
* Hide security options display for endpoint when none is required.
* Correctly display the schema title in the schema-tree.
* Add links to component schema when clicked in bodies of objects.

## 2.0
* `show-server-selection` has now be inverted to be `hide-server-selection` this brings it in line with how html boolean attributes are supposed to work. If you set this value to false previously, now you can hide the section using the new property.
Expand Down
28 changes: 19 additions & 9 deletions src/components/schema-table.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,10 @@ export default class SchemaTable extends LitElement {

/* eslint-disable indent */
render() {
const displayLine = [this.data?.['::title'], this.data?.['::description']].filter(d => d).join(' - ');
return html`
${this.data && this.data['::description']
? html`<span class='m-markdown' style="padding-bottom: 8px;"> ${unsafeHTML(marked(this.data['::description'] || ''))}</span>`
${displayLine
? html`<span class='m-markdown' style="padding-bottom: 8px;"> ${unsafeHTML(marked(displayLine))}</span>`
: ''
}
<div class="table ${this.interactive ? 'interactive' : ''}">
Expand All @@ -136,6 +137,10 @@ export default class SchemaTable extends LitElement {
`;
}

scrollToSchemaComponentByName(componentName) {
this.dispatchEvent(new CustomEvent('scrollToSchemaComponentByName', { bubbles: true, composed: true, detail: componentName }));
}

generateTree(data, dataType = 'object', key = '', title = '', description = '', schemaLevel = 0, indentLevel = 0) {
const newSchemaLevel = data['::type'] && data['::type'].startsWith('xxx-of') ? schemaLevel : (schemaLevel + 1);
const newIndentLevel = dataType === 'xxx-of-option' || data['::type'] === 'xxx-of-option' || key.startsWith('::OPTION') ? indentLevel : (indentLevel + 1);
Expand Down Expand Up @@ -163,20 +168,22 @@ export default class SchemaTable extends LitElement {
}

let detailObjType = '';
let displaySchemaLink = false;
if ((data['::type'] || '').includes('xxx-of')) {
detailObjType = '';
} else if (data['::type'] === 'object') {
if (dataType === 'array') {
detailObjType = `[${keyLabel.replace(/(s|Collection|List)[*]?$/i, '')}]`; // Array of Object
} else {
detailObjType = 'object'; // Object
}
} else if (data['::type'] === 'array') {
if (dataType === 'array') {
detailObjType = 'array of array'; // Array of array
} else {
detailObjType = 'array';
}
} else if (data['::type']) {
displaySchemaLink = data['::link'];
if (dataType === 'array') {
detailObjType = `[${data['::link']}]`; // Array of Object
} else {
detailObjType = data['::link'] || data['::type'];
}
}

if (typeof data === 'object') {
Expand Down Expand Up @@ -205,7 +212,10 @@ export default class SchemaTable extends LitElement {
</div>
</div>
<div class='td key-type'>
<div>${(data['::type'] || '').includes('xxx-of') ? '' : detailObjType}</div>
${displaySchemaLink
? html`<div class="schema-link" style="overflow: hidden; text-overflow: ellipsis" @click='${() => this.scrollToSchemaComponentByName(displaySchemaLink)}'>${detailObjType}</div>`
: html`<div>${(data['::type'] || '').includes('xxx-of') ? '' : detailObjType}</div>`
}
<div class="attributes" title="${flags['🆁'] && 'Read only attribute' || flags['🆆'] && 'Write only attribute' || ''}">${flags['🆁'] || flags['🆆'] || ''}</div>
</div>
<div class='td key-descr'>
Expand Down
12 changes: 8 additions & 4 deletions src/openapi-explorer.js
Original file line number Diff line number Diff line change
Expand Up @@ -306,11 +306,7 @@ export default class OpenApiExplorer extends LitElement {
position: relative;
padding: 6px 0px;
}
.expanded-endpoint-component > h2:hover {
cursor: pointer;
text-decoration: underline;
}
.divider {
border-top: 2px solid var(--border-color);
margin: 24px 0;
Expand Down Expand Up @@ -764,6 +760,14 @@ export default class OpenApiExplorer extends LitElement {
}, 300);
}

async scrollToSchemaComponentByName(schemaComponentNameEvent) {
const schemaComponentName = schemaComponentNameEvent.detail;
const schemaComponent = this.resolvedSpec?.components?.find(c => c.componentKeyId === 'schemas')?.subComponents?.find(s => s.name === schemaComponentName);
if (schemaComponent) {
await this.scrollTo(`cmp--${schemaComponent.id}`, true);
}
}

// Public Method (scrolls to a given path and highlights the left-nav selection)
async scrollTo(elementId, scrollNavItemToView = true, repeatedElementIndex) {
try {
Expand Down
5 changes: 5 additions & 0 deletions src/styles/schema-styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,4 +106,9 @@ export default css`
display: flex;
}
}
.expanded-endpoint-component > h2:hover, .schema-link:hover {
cursor: pointer;
text-decoration: underline;
}
`;
2 changes: 2 additions & 0 deletions src/templates/callback-template.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export default function callbackTemplate(callbacks) {
schema-expand-level = "${this.schemaExpandLevel}"
schema-hide-read-only = "${this.schemaHideReadOnly}"
fetch-credentials = "${this.fetchCredentials}"
@scrollToSchemaComponentByName=${v => this.scrollToSchemaComponentByName(v)}
exportparts="btn btn-fill btn-outline btn-try">
</api-request>
Expand All @@ -47,6 +48,7 @@ export default function callbackTemplate(callbacks) {
schema-style="${this.displaySchemaAsTable ? 'table' : 'tree'}"
active-schema-tab = "${this.defaultSchemaTab}"
schema-expand-level = "${this.schemaExpandLevel}"
@scrollToSchemaComponentByName=${v => this.scrollToSchemaComponentByName(v)}
exportparts = "btn--resp btn-fill--resp btn-outline--resp"
> </api-response>
</div>
Expand Down
5 changes: 3 additions & 2 deletions src/templates/components-template.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ function componentBodyTemplate(sComponent) {
const formdataPartSchema = schemaInObjectNotation(sComponent.component, { includeNulls: this.includeNulls });

return html`
<div class='expanded-endpoint-component observe-me ${sComponent.name}' id='cmp--${sComponent.id}' @click='${() => this.scrollTo(`cmp--${sComponent.id}`)}'>
<h2>${sComponent.name}</h2>
<div class='expanded-endpoint-component observe-me ${sComponent.name}' id='cmp--${sComponent.id}'>
<h2 @click='${() => this.scrollTo(`cmp--${sComponent.id}`)}'>${sComponent.name}</h2>
<div class='mono-font regular-font-size' style='padding: 8px 0; color:var(--fg2)'>
${this.displaySchemaAsTable
? html`<schema-table
.data = '${formdataPartSchema}'
@scrollToSchemaComponentByName=${v => this.scrollToSchemaComponentByName(v)}
schema-expand-level = "${this.schemaExpandLevel}"
schema-hide-read-only=false
schema-hide-write-only=false> </schema-table>`
Expand Down
2 changes: 2 additions & 0 deletions src/templates/endpoint-template.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ function endpointBodyTemplate(path) {
schema-expand-level = "${this.schemaExpandLevel}"
schema-hide-read-only = "${this.schemaHideReadOnly}"
fetch-credentials = "${this.fetchCredentials}"
@scrollToSchemaComponentByName=${v => this.scrollToSchemaComponentByName(v)}
exportparts="btn btn-fill btn-outline btn-try">
</api-request>
</div>
Expand All @@ -122,6 +123,7 @@ function endpointBodyTemplate(path) {
schema-expand-level = "${this.schemaExpandLevel}"
schema-hide-write-only = "${this.schemaHideWriteOnly}"
selected-status = "${Object.keys(path.responses || {})[0] || ''}"
@scrollToSchemaComponentByName=${v => this.scrollToSchemaComponentByName(v)}
exportparts = "btn--resp btn-fill--resp btn-outline--resp"
> </api-response>
</div>
Expand Down
2 changes: 2 additions & 0 deletions src/templates/expanded-endpoint-template.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export function expandedEndpointBodyTemplate(path, tagName = '') {
schema-expand-level = "${this.schemaExpandLevel}"
schema-hide-read-only = "${this.schemaHideReadOnly}"
fetch-credentials = "${this.fetchCredentials}"
@scrollToSchemaComponentByName=${v => this.scrollToSchemaComponentByName(v)}
exportparts = "btn btn-fill btn-outline btn-try"
> </api-request>
Expand All @@ -82,6 +83,7 @@ export function expandedEndpointBodyTemplate(path, tagName = '') {
schema-expand-level = "${this.schemaExpandLevel}"
schema-hide-write-only = "${this.schemaHideWriteOnly}"
selected-status = "${Object.keys(path.responses || {})[0] || ''}"
@scrollToSchemaComponentByName=${v => this.scrollToSchemaComponentByName(v)}
exportparts = "btn--resp btn-fill--resp btn-outline--resp"
> </api-response>
</div>
Expand Down
13 changes: 10 additions & 3 deletions src/utils/schema-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,9 @@ export function schemaInObjectNotation(rawSchema, options, level = 0, suffix = '
if (Object.keys(objWithAnyOfProps).length) {
resultObj[(anyOf ? `::ANY~OF ${suffix}` : `::ONE~OF ${suffix}`)] = objWithAnyOfProps;
}
resultObj['::type'] = 'object';

resultObj['::link'] = schema.title;
resultObj['::type'] = schema.title || 'object';
resultObj['::flags'] = { '🆁': readOnly && '🆁', '🆆': writeOnly && '🆆' };
resultObj['::title'] = schema.title || '';
resultObj['::description'] = schema.description || '';
Expand Down Expand Up @@ -410,6 +412,7 @@ export function schemaInObjectNotation(rawSchema, options, level = 0, suffix = '
}
}
if (complexTypes.length > 0) {
obj['::link'] = schema.title;
obj['::type'] = 'object';
const multiTypeOptions = {
'::type': 'xxx-of-option',
Expand All @@ -429,7 +432,8 @@ export function schemaInObjectNotation(rawSchema, options, level = 0, suffix = '
'::title': schema.title || '',
'::description': schema.description || '',
'::flags': { '🆁': schema.readOnly && '🆁', '🆆': schema.writeOnly && '🆆' },
'::type': 'object',
'::link': schema.title,
'::type': schema.title || 'object',
'::deprecated': schema.deprecated || false,
'::metadata': metadata
};
Expand All @@ -446,6 +450,7 @@ export function schemaInObjectNotation(rawSchema, options, level = 0, suffix = '
'::title': schema.title || '',
'::description': schema.description || '',
'::flags': { '🆁': schema.readOnly && '🆁', '🆆': schema.writeOnly && '🆆' },
'::link': arrayItemsSchema.title || schema.title,
'::type': 'array',
// Array properties are read from the ::props object instead of reading from the keys of this object
// '::props': schemaInObjectNotation(Object.assign({ deprecated: schema.deprecated, readOnly: schema.readOnly, writeOnly: schema.writeOnly }, arrayItemsSchema), options, (level + 1)),
Expand All @@ -464,7 +469,8 @@ export function schemaInObjectNotation(rawSchema, options, level = 0, suffix = '
obj['::title'] = schema.title || '';
obj['::description'] = schema.description || '';
obj['::flags'] = { '🆁': schema.readOnly && '🆁', '🆆': schema.writeOnly && '🆆' };
obj['::type'] = 'object';
obj['::link'] = schema.title;
obj['::type'] = schema.title || 'object';
obj['::deprecated'] = schema.deprecated || false;
obj['::metadata'] = metadata;
for (const key in schemaProperties) {
Expand All @@ -486,6 +492,7 @@ export function schemaInObjectNotation(rawSchema, options, level = 0, suffix = '
obj['::title'] = schema.title || '';
obj['::description'] = schema.description || (arrayItemsSchema?.description ? `array&lt;${arrayItemsSchema.description}&gt;` : '');
obj['::flags'] = { '🆁': schema.readOnly && '🆁', '🆆': schema.writeOnly && '🆆' };
obj['::link'] = arrayItemsSchema.title || schema.title;
obj['::type'] = 'array';
obj['::deprecated'] = schema.deprecated || false;
obj['::metadata'] = metadata;
Expand Down

0 comments on commit c87337f

Please sign in to comment.