Skip to content

Commit

Permalink
Add interface debugger (directus#61)
Browse files Browse the repository at this point in the history
* Add /interfaces overview route

* Update route to be plural

* Add interface debugger route

* Render interface to screen

* Add form for interface settings

* Add misc section to settings

* Add some styling to show width

* Add output preview

* Add options form

* Add missing global for readonly interface

* Add readonly to interface debugger page
  • Loading branch information
rijkvanzanten committed Mar 26, 2018
1 parent 7c2e7b0 commit 0e718b6
Show file tree
Hide file tree
Showing 6 changed files with 259 additions and 4 deletions.
14 changes: 11 additions & 3 deletions src/components/extensions/InterfaceExtension.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
:is="componentName"
:name="name"
:value="value"
:type="type"
:length="length"
:type="typeOrDefault"
:length="lengthOrDefault"
:readonly="readonly"
:required="required"
:loading="loading"
Expand Down Expand Up @@ -37,7 +37,7 @@ export default {
},
type: {
type: String,
required: true,
default: null,
},
length: {
type: [String, Number],
Expand Down Expand Up @@ -70,6 +70,14 @@ export default {
componentName() {
return `interface-${this.id}`;
},
typeOrDefault() {
if (!this.interface) return null;
return this.type ? this.type : Object.keys(this.interface.dataTypes)[0];
},
lengthOrDefault() {
if (!this.interface) return null;
return this.length ? this.length : this.interface.dataTypes[this.typeOrDefault];
},
optionsWithDefaults() {
if (!this.interface) return {};
Expand Down
2 changes: 2 additions & 0 deletions src/globals.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import VTable from './components/VTable.vue';
import ListingExtension from './components/extensions/ListingExtension.vue';
import ListingOptionsExtension from './components/extensions/ListingOptionsExtension.vue';
import InterfaceExtension from './components/extensions/InterfaceExtension.vue';
import ReadonlyExtension from './components/extensions/ReadonlyExtension.vue';

Vue.component('header-button', HeaderButton);
Vue.component('breadcrumb', Breadcrumb);
Expand All @@ -35,3 +36,4 @@ Vue.component('v-table', VTable);
Vue.component('listing-extension', ListingExtension);
Vue.component('listing-options-extension', ListingOptionsExtension);
Vue.component('interface-extension', InterfaceExtension);
Vue.component('readonly-extension', ReadonlyExtension);
11 changes: 11 additions & 0 deletions src/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import ItemListing from './routes/ItemListing.vue';
import Edit from './routes/Edit.vue';
import Login from './routes/Login.vue';
import NotFound from './routes/NotFound.vue';
import Interfaces from './routes/Interfaces.vue';
import InterfaceDebugger from './routes/InterfaceDebugger.vue';

Vue.use(Router);

Expand All @@ -31,6 +33,15 @@ const router = new Router({
props: true,
component: Edit,
},
{
path: '/interfaces',
component: Interfaces,
},
{
path: '/interfaces/:id',
component: InterfaceDebugger,
props: true,
},
{
path: '/login',
component: Login,
Expand Down
198 changes: 198 additions & 0 deletions src/routes/InterfaceDebugger.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
<template>
<div class="interface-debugger">
<portal to="header-title">
<breadcrumb :links="links" />
</portal>

<div
:style="{ width: width + 'px' }"
class="box">
<interface-extension
v-model="value"
:id="id"
:name="id"
:type="type"
:length="length"
:readonly="readonly"
:required="required"
:loading="loading"
:options="options" />
</div>

<output>{{ value }}</output>

<div
:style="{ width: width + 'px' }"
class="box">
<readonly-extension
v-model="value"
:id="id"
:name="id"
:type="type"
:length="length"
:readonly="readonly"
:required="required"
:loading="loading"
:options="options" />
</div>

<form @submit.prevent>
<fieldset>
<legend>Settings</legend>

<label for="type">Type</label>
<select
id="type"
v-model="type">
<option
v-for="(length, type) in extension.dataTypes"
:key="type"
:value="type"
>{{ type }}</option>
</select>

<label for="length">Length</label>
<input
id="length"
v-model="length"
type="number"
min="0">

<label for="readonly">Read only</label>
<input
id="readonly"
v-model="readonly"
type="checkbox">


<label for="required">Required</label>
<input
id="required"
v-model="required"
type="checkbox">

<label for="loading">Loading</label>
<input
id="loading"
v-model="loading"
type="checkbox">
</fieldset>
<fieldset>
<legend>Options</legend>
<div
v-for="(option, optionID) in extension.options"
:key="optionID">
<label :for="optionID">{{ option.name }}</label>
<p>{{ option.comment }}</p>
<interface-extension
v-model="options[optionID]"
:id="optionID"
:name="optionID"
:type="option.type"
:length="option.length"
:readonly="option.readonly"
:required="option.required"
:loading="option.loading"
:options="option.options" />
</div>
</fieldset>
<fieldset>
<legend>Misc.</legend>
<label for="width">Responsiveness tester</label>
<input
id="width"
v-model="width"
min="50"
max="1000"
step="1"
type="range">
<span>{{ width }}px</span>
</fieldset>
</form>
</div>
</template>

<script>
export default {
name: 'interface-debugger',
props: {
id: {
type: String,
required: true,
},
},
data() {
return {
type: null,
length: null,
value: null,
readonly: false,
required: false,
loading: false,
options: {},
width: 200,
};
},
computed: {
links() {
return [
{
name: 'Interfaces',
path: '/interfaces',
},
{
name: this.extension.name,
path: `/interfaces/${this.id}`,
},
];
},
extension() {
return this.$store.state.extensions.interfaces.data[this.id];
},
},
watch: {
id() {
this.hydrate();
},
type() {
this.length = this.extension.dataTypes[this.type];
},
},
created() {
this.hydrate();
},
methods: {
hydrate() {
// Set type to the first datatype available in the meta info
this.type = Object.keys(this.extension.dataTypes)[0];
// Populate the options with the default values
const defaults = this.$lodash.mapValues(
this.extension.options,
settings => settings.default || null,
);
this.options = defaults;
},
},
};
</script>

<style scoped>
.interface-debugger {
padding: 10px;
}
.box {
border: 1px solid var(--lighter-gray);
padding: 10px;
margin-bottom: 20px;
}
output {
background-color: white;
padding: 10px;
margin: 10px 0;
font-family: monospace;
display: block;
}
</style>
36 changes: 36 additions & 0 deletions src/routes/Interfaces.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<template>
<v-table
:columns="columns"
:items="items"
link="__link"
primary-key-field="id" />
</template>

<script>
export default {
computed: {
items() {
return Object.keys(this.$store.state.extensions.interfaces.data).map(id => ({
...this.$store.state.extensions.interfaces.data[id],
__link: `/interfaces/${id}`,
}));
},
columns() {
return [
{
field: 'name',
name: 'Name',
},
{
field: 'id',
name: 'id',
},
{
field: 'version',
name: 'Version',
},
];
},
},
};
</script>
2 changes: 1 addition & 1 deletion src/store/modules/auth/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ export function login({ commit }, credentials) {
...credentials,
persist: true,
})
.then(hydrateStore)
.then(info => commit('LOGIN_SUCCESS', {
...info,
projectName: config.api[info.url] || extractHostname(info.url),
}))
.then(hydrateStore)
.then(resolve)
.catch((error) => {
commit('LOGIN_FAILED', error);
Expand Down

0 comments on commit 0e718b6

Please sign in to comment.