Skip to content

Commit

Permalink
Support for OpenAPI properties
Browse files Browse the repository at this point in the history
  • Loading branch information
avillar committed Apr 16, 2024
1 parent 44989c6 commit 3544b98
Show file tree
Hide file tree
Showing 3 changed files with 281 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/components/BuildingBlock.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
Examples
</v-tab>
<v-tab value="json-schema" prepend-icon="mdi-code-json" v-if="bblock.schema">JSON Schema</v-tab>
<v-tab value="openapi" prepend-icon="mdi-api" v-if="bblock.openAPIDocument">OpenAPI document</v-tab>
<v-tab value="json-ld" prepend-icon="mdi-semantic-web" v-if="bblock.ldContext">JSON-LD context</v-tab>
<v-tab value="validation" prepend-icon="mdi-check" v-if="shaclRules">Validation</v-tab>
</v-tabs>
Expand Down Expand Up @@ -179,6 +180,9 @@
<v-window-item value="json-schema" :transition="false" :reverse-transition="false">
<json-schema-viewer :bblock="bblock"></json-schema-viewer>
</v-window-item>
<v-window-item value="openapi" :transition="false" :reverse-transition="false">
<open-api-document-viewer :bblock="bblock"></open-api-document-viewer>
</v-window-item>
<v-window-item v-if="bblock.ldContext" value="json-ld" :transition="false" :reverse-transition="false">
<json-ld-context-viewer :bblock="bblock"></json-ld-context-viewer>
</v-window-item>
Expand Down Expand Up @@ -271,6 +275,7 @@ import LanguageTabs from "@/components/bblock/LanguageTabs.vue";
import JsonSchemaViewer from "@/components/bblock/JsonSchemaViewer.vue";
import ColorCircle from "@/components/ColorCircle.vue";
import CopyToClipboardButton from "@/components/CopyToClipboardButton.vue";
import OpenApiDocumentViewer from "@/components/bblock/OpenApiDocumentViewer.vue";
export default {
components: {
Expand All @@ -281,6 +286,7 @@ export default {
JsonLdContextViewer,
DependencyViewer,
ExampleViewer,
OpenApiDocumentViewer,
},
props: {
bblockId: String,
Expand Down
261 changes: 261 additions & 0 deletions src/components/bblock/OpenApiDocumentViewer.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
<template>
<div class="openapi-document-viewer">
<p class="mb-2">This Building Block's OpenAPI document is available at the following URL:</p>

<div class="text-right mb-2" v-if="bblock?.openAPIDocument">
<v-btn-toggle
v-model="mode"
rounded="0"
color="primary"
group
>
<v-btn value="source">
Source
<template #append>
<v-tooltip
text="The source version shows the document before resolving Building Blocks references"
class="opaque-tooltip"
location="bottom"
>
<template #activator="{ props }">
<v-icon v-bind="props">mdi-help-circle</v-icon>
</template>
</v-tooltip>
</template>
</v-btn>
<v-btn value="final">
Final
<template #append>
<v-tooltip
text="The final document only contains resolved Building Blocks references."
class="opaque-tooltip"
location="bottom"
>
<template #activator="{ props }">
<v-icon v-bind="props">mdi-help-circle</v-icon>
</template>
</v-tooltip>
</template>
</v-btn>
</v-btn-toggle>
</div>

<div class="ml-3">
<div v-if="url" class="d-flex align-center mb-2">
<copy-text-field url :text="url"></copy-text-field>
</div>
</div>

<div class="d-flex flex-column align-stretch pa-5">
<div class="code-viewer-wrapper">
<code-viewer
v-if="contents"
language="yaml"
:code="contents"
:open-urls="false"
@code-click="codeClick"
></code-viewer>
</div>
<div v-if="contents" class="openapi-actions text-right mt-1">
<v-btn
prepend-icon="mdi-clipboard"
@click="copyToClipboard(contents)"
color="primary"
variant="flat"
>
Copy to clipboard
</v-btn>
</div>
<v-progress-circular v-if="loading" size="64"></v-progress-circular>
</div>
<v-menu
v-model="menu.visible"
:activator="menu.activator"
min-width="0"
@click:outside="clickOutside"
persistent
no-click-animation
>
<v-card>
<v-card-text v-if="!menu.loading">
<div>From <strong>{{ menu.bblock.name }}</strong></div>
<div><small><code>{{ menu.bblock.itemIdentifier }}</code></small></div>
<div v-if="menu.bblock.register" style="font-size: 90%">
<color-circle :color="menu.bblock.register.color"></color-circle>
{{ menu.bblock.register.name }}
</div>
<div class="text-center mt-2">
<v-btn
v-if="canOpenBBlock(menu.bblock)"
size="small"
class="mx-1"
@click.prevent="openBBlock(menu.bblock)"
>
View Building Block
</v-btn>
<v-btn size="small" class="mx-1" @click.prevent="openUrl(menu.href)">Open schema</v-btn>
</div>
</v-card-text>
<v-card-text v-else class="text-center">
<v-progress-circular indeterminate size="32"></v-progress-circular>
</v-card-text>
</v-card>
</v-menu>
</div>
</template>
<script>
import CopyTextField from "@/components/CopyTextField.vue";
import CodeViewer from "@/components/CodeViewer.vue";
import {copyToClipboard} from "@/lib/utils";
import bblockService from "@/services/bblock.service";
import ColorCircle from "@/components/ColorCircle.vue";
export default {
components: {
ColorCircle,
CopyTextField,
CodeViewer,
},
props: {
bblock: {
type: Object,
required: true,
},
},
data() {
return {
finalDocument: {
loading: false,
contents: null,
},
sourceDocument: {
loading: false,
contents: null,
},
mode: 'final', // or 'simplified'
menu: {
loading: false,
activator: null,
visible: false,
bblock: null,
href: null,
},
};
},
methods: {
copyToClipboard,
load() {
if (!this.bblock?.openAPIDocument) {
return;
}
let prop = 'openAPIDocument', document = this.finalDocument;
if (this.mode !== 'final') {
prop = 'sourceOpenAPIDocument';
document = this.sourceDocument;
}
if (!document.contents) {
document.loading = true;
bblockService.fetchDocument(this.bblock, prop)
.then(data => document.contents = data)
.finally(() => document.loading = false);
}
},
async codeClick({ target, href }) {
this.menu.loading = true;
let bblock;
try {
const textContent = target.textContent.trim();
if (/^bblocks:\/\//.test(textContent)) {
const bblockId = textContent.substring(10);
let bblocks = await bblockService.getBBlocks(false);
if (!bblocks[bblockId]) {
bblocks = await bblockService.getBBlocks(true);
}
bblock = bblocks[bblockId];
if (bblock) {
href = bblock.openAPIDocument || bblock.schema?.['application/yaml'];
} else {
href = null;
}
} else if (href) {
bblock = await bblockService.findResource(href);
console.log(href, bblock)
if (!bblock) {
window.open(href);
return;
}
}
} finally {
this.menu.loading = false;
}
if (bblock) {
this.menu.activator = target;
this.menu.bblock = bblock;
this.menu.href = href;
this.$nextTick(() => this.menu.visible = true);
}
},
openUrl(url) {
window.open(url);
},
openBBlock(bblock) {
if (bblockService.isShown(bblock)) {
this.$router.push({
name: 'BuildingBlock',
params: {
id: bblock.itemIdentifier,
},
});
} else if (bblock.documentation?.['bblocks-viewer']) {
window.open(bblock.documentation['bblocks-viewer'].url);
}
},
canOpenBBlock(bblock) {
return bblockService.isShown(bblock) || bblock.documentation?.['bblocks-viewer'];
},
clickOutside(ev) {
this.$nextTick(() => {
if (ev.target !== this.menu.activator) {
this.menu.visible = false;
}
});
},
},
computed: {
contents() {
if (!this.bblock) {
return null;
}
return this.mode === 'final' ? this.finalDocument.contents : this.sourceDocument.contents;
},
url() {
if (!this.bblock) {
return null;
}
return this.mode === 'final' ? this.bblock.openAPIDocument : this.bblock.sourceOpenAPIDocument;
},
loading() {
return this.mode === 'final' ? this.finalDocument.loading : this.sourceDocument.loading;
},
},
watch: {
bblock: {
handler() {
this.finalDocument.contents = null;
this.sourceDocument.contents = null;
this.mode = 'final';
this.load();
},
immediate: true,
},
mode() {
this.load();
},
},
}
</script>
<style>
.opaque-tooltip .v-overlay__content {
background: rgba(66, 66, 66, 1) !important;
}
</style>
14 changes: 14 additions & 0 deletions src/services/bblock.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,13 @@ class BBlockService {
this.resourceMappings[bblock.sourceSchema] = bblock.itemIdentifier;
}
}
if (bblock.openAPIDocument) {
console.log('adding', bblock.openAPIDocument)
this.resourceMappings[bblock.openAPIDocument] = bblock.itemIdentifier;
if (bblock.sourceOpenAPIDocument) {
this.resourceMappings[bblock.sourceOpenAPIDocument] = bblock.itemIdentifier;
}
}

}
this.loadedRegistersCount++;
Expand Down Expand Up @@ -196,6 +203,13 @@ class BBlockService {
return null;
}

async fetchDocument(bblock, property) {
if (bblock[property]) {
return (await client.get(bblock[property], {responseType: 'text'})).data;
}
return null;
}

isShown(bblockOrImportLevel) {
const showLevel = configService.config.showImported;
if (showLevel === true) {
Expand Down

0 comments on commit 3544b98

Please sign in to comment.