Merge pull request #314 from SAP-samples/data-browser
Data browser Cosmetics
This commit is contained in:
@@ -8,7 +8,7 @@
|
|||||||
"mocha": true
|
"mocha": true
|
||||||
},
|
},
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"ecmaVersion": 2018
|
"ecmaVersion": 2020
|
||||||
},
|
},
|
||||||
"globals": {
|
"globals": {
|
||||||
"SELECT": true,
|
"SELECT": true,
|
||||||
|
|||||||
@@ -2,12 +2,19 @@
|
|||||||
const GET = (url) => axios.get('/-data'+url)
|
const GET = (url) => axios.get('/-data'+url)
|
||||||
const storageGet = (key, def) => localStorage.getItem('data-viewer:'+key) || def
|
const storageGet = (key, def) => localStorage.getItem('data-viewer:'+key) || def
|
||||||
const storageSet = (key, val) => localStorage.setItem('data-viewer:'+key, val)
|
const storageSet = (key, val) => localStorage.setItem('data-viewer:'+key, val)
|
||||||
|
const columnKeysFirst = (c1, c2) => {
|
||||||
|
if (c1.isKey && !c2.isKey) return -1
|
||||||
|
if (!c1.isKey && c2.isKey) return 1
|
||||||
|
if (c1.isKey && c2.isKey) return c1.name.localeCompare(c2.name)
|
||||||
|
return 0 // retain natural order of normal columns
|
||||||
|
}
|
||||||
|
|
||||||
const vue = new Vue ({
|
const vue = new Vue ({
|
||||||
|
|
||||||
el:'#app',
|
el:'#app',
|
||||||
|
|
||||||
data: {
|
data: {
|
||||||
|
error: undefined,
|
||||||
dataSource: storageGet('data-source', 'db'),
|
dataSource: storageGet('data-source', 'db'),
|
||||||
skip: storageGet('skip', 0),
|
skip: storageGet('skip', 0),
|
||||||
top: storageGet('top', 20),
|
top: storageGet('top', 20),
|
||||||
@@ -32,6 +39,7 @@ const vue = new Vue ({
|
|||||||
if (vue.dataSource === 'db') url += `?dataSource=db`
|
if (vue.dataSource === 'db') url += `?dataSource=db`
|
||||||
const {data} = await GET(url)
|
const {data} = await GET(url)
|
||||||
vue.entities = data.value
|
vue.entities = data.value
|
||||||
|
vue.entities.forEach(entity => entity.columns.sort(columnKeysFirst))
|
||||||
const entity = vue.entity && vue.entities.find(e => e.name === vue.entity.name)
|
const entity = vue.entity && vue.entities.find(e => e.name === vue.entity.name)
|
||||||
if (entity) { // restore selection from previous fetch
|
if (entity) { // restore selection from previous fetch
|
||||||
vue.columns = entity.columns
|
vue.columns = entity.columns
|
||||||
@@ -54,11 +62,30 @@ const vue = new Vue ({
|
|||||||
async fetchData () {
|
async fetchData () {
|
||||||
let url = `/Data?entity=${vue.entity.name}&$skip=${vue.skip}&$top=${vue.top}`
|
let url = `/Data?entity=${vue.entity.name}&$skip=${vue.skip}&$top=${vue.top}`
|
||||||
if (vue.dataSource === 'db') url += `&dataSource=db`
|
if (vue.dataSource === 'db') url += `&dataSource=db`
|
||||||
const {data} = await GET(url)
|
|
||||||
vue.data = data.value.map(d => d.record.map(r => r.data))
|
try {
|
||||||
const row = vue.data.find(data => vue._makeRowKey(data) === vue.rowKey)
|
const {data} = await GET(url)
|
||||||
if (row) vue._setRowDetails(row)
|
// sort data along column order
|
||||||
else vue.rowDetails = {}
|
const columnIndexes = {}
|
||||||
|
vue.columns.forEach((col, i) => columnIndexes[col.name] = i)
|
||||||
|
vue.data = data.value.map(d => d.record
|
||||||
|
.sort((r1, r2) => columnIndexes[r1.column] - columnIndexes[r2.column])
|
||||||
|
.map(r => r.data)
|
||||||
|
)
|
||||||
|
const row = vue.data.find(data => vue._makeRowKey(data) === vue.rowKey)
|
||||||
|
if (row) vue._setRowDetails(row)
|
||||||
|
else vue.rowDetails = {}
|
||||||
|
vue.error = undefined
|
||||||
|
} catch (err) {
|
||||||
|
if (err.response?.data?.error) {
|
||||||
|
vue.error = err.response?.data?.error
|
||||||
|
} else {
|
||||||
|
vue.error = err
|
||||||
|
}
|
||||||
|
vue.data = []
|
||||||
|
vue.rowDetails = {}
|
||||||
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
inspectRow (eve) {
|
inspectRow (eve) {
|
||||||
|
|||||||
@@ -7,13 +7,14 @@
|
|||||||
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
|
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
|
||||||
<style>
|
<style>
|
||||||
|
th { position: sticky; top:0; z-index: 2; background-color: white; }
|
||||||
.noscroll { overflow: hidden; }
|
.noscroll { overflow: hidden; }
|
||||||
.hovering tr:hover td { background: #ebeefc; cursor: pointer; }
|
.hovering tr:hover td { background: #ebeefc; cursor: pointer; }
|
||||||
.highlight { background: #ebeefc !important; }
|
.highlight { background: #ebeefc !important; }
|
||||||
.rating-stars { color:teal }
|
.rating-stars { color:teal }
|
||||||
.succeeded { color:teal }
|
.succeeded { color:teal }
|
||||||
.failed { color:red }
|
.failed { color:red }
|
||||||
.condensed { max-width: 100px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
.condensed { max-width: 100px; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
.key { font-weight: bold }
|
.key { font-weight: bold }
|
||||||
.not-key { font-weight: lighter;}
|
.not-key { font-weight: lighter;}
|
||||||
.with-sidebar { display: flex; flex-wrap: wrap; gap: 1rem; }
|
.with-sidebar { display: flex; flex-wrap: wrap; gap: 1rem; }
|
||||||
@@ -24,6 +25,7 @@
|
|||||||
.not-sidebar-sub { max-height: 40vh; overflow-y: scroll; }
|
.not-sidebar-sub { max-height: 40vh; overflow-y: scroll; }
|
||||||
.horizontal label { display: inline; }
|
.horizontal label { display: inline; }
|
||||||
.horizontal input { width: initial; display: inline; }
|
.horizontal input { width: initial; display: inline; }
|
||||||
|
.error { color: red; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@@ -60,7 +62,7 @@
|
|||||||
<label for="top">Top:</label>
|
<label for="top">Top:</label>
|
||||||
<input id="top" v-model.lazy="top" title="No. of entries to read" type="number" min="0">
|
<input id="top" v-model.lazy="top" title="No. of entries to read" type="number" min="0">
|
||||||
</div>
|
</div>
|
||||||
<div v-if="entity" class="not-sidebar-main">
|
<div v-if="data" class="not-sidebar-main">
|
||||||
<table id='data' class="hovering striped-table condensed">
|
<table id='data' class="hovering striped-table condensed">
|
||||||
<thead>
|
<thead>
|
||||||
<th v-for="col in columns" :title="col.type" :class="[col.isKey ? 'key' : 'not-key']">{{ col.name }} </th>
|
<th v-for="col in columns" :title="col.type" :class="[col.isKey ? 'key' : 'not-key']">{{ col.name }} </th>
|
||||||
@@ -70,6 +72,9 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="error" class="not-sidebar-main error">
|
||||||
|
Error: {{ error.code }} – {{ error.message }}
|
||||||
|
</div>
|
||||||
<p></p>
|
<p></p>
|
||||||
<div v-if="rowDetails" class="not-sidebar-sub">
|
<div v-if="rowDetails" class="not-sidebar-sub">
|
||||||
<table id='rowDetails'>
|
<table id='rowDetails'>
|
||||||
|
|||||||
Reference in New Issue
Block a user