2020-03-10 14:53:23 +01:00
|
|
|
<script>
|
2020-04-06 16:38:33 +02:00
|
|
|
import { onMount, getContext } from "svelte"
|
2020-03-31 13:16:03 +02:00
|
|
|
import { store, backendUiStore } from "builderStore"
|
2020-03-25 17:59:32 +01:00
|
|
|
import {
|
|
|
|
tap,
|
|
|
|
get,
|
|
|
|
find,
|
|
|
|
last,
|
|
|
|
compose,
|
|
|
|
flatten,
|
|
|
|
map,
|
|
|
|
remove,
|
2020-03-27 17:58:32 +01:00
|
|
|
keys,
|
2020-03-31 13:16:03 +02:00
|
|
|
takeRight,
|
2020-03-25 17:59:32 +01:00
|
|
|
} from "lodash/fp"
|
2020-03-31 13:16:03 +02:00
|
|
|
import Select from "components/common/Select.svelte"
|
|
|
|
import { getIndexSchema } from "components/common/core"
|
|
|
|
import ActionButton from "components/common/ActionButton.svelte"
|
2020-03-12 15:23:29 +01:00
|
|
|
import TablePagination from "./TablePagination.svelte"
|
2020-04-06 16:38:33 +02:00
|
|
|
import { DeleteRecordModal, CreateEditRecordModal } from "./modals"
|
2020-03-12 15:23:29 +01:00
|
|
|
import * as api from "./api"
|
2020-03-10 17:06:30 +01:00
|
|
|
|
2020-04-06 16:38:33 +02:00
|
|
|
const { open, close } = getContext("simple-modal")
|
|
|
|
|
|
|
|
const editRecord = async row => {
|
|
|
|
open(
|
|
|
|
CreateEditRecordModal,
|
|
|
|
{
|
|
|
|
onClosed: close,
|
|
|
|
record: await selectRecord(row),
|
|
|
|
},
|
|
|
|
{ styleContent: { padding: "0" } }
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2020-04-06 16:44:53 +02:00
|
|
|
const deleteRecord = async row => {
|
|
|
|
open(
|
|
|
|
DeleteRecordModal,
|
|
|
|
{
|
|
|
|
onClosed: close,
|
|
|
|
record: await selectRecord(row),
|
|
|
|
},
|
|
|
|
{ styleContent: { padding: "0" } }
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2020-04-06 16:38:33 +02:00
|
|
|
async function selectRecord(record) {
|
|
|
|
return await api.loadRecord(record.key, {
|
|
|
|
appname: $store.appname,
|
|
|
|
instanceId: $backendUiStore.selectedDatabase.id,
|
|
|
|
})
|
|
|
|
}
|
2020-03-12 15:23:29 +01:00
|
|
|
|
2020-03-22 12:35:35 +01:00
|
|
|
const ITEMS_PER_PAGE = 10
|
2020-03-25 17:59:32 +01:00
|
|
|
// Internal headers we want to hide from the user
|
2020-03-27 17:58:32 +01:00
|
|
|
const INTERNAL_HEADERS = ["key", "sortKey", "type", "id", "isNew"]
|
2020-03-22 10:21:18 +01:00
|
|
|
|
2020-03-12 15:23:29 +01:00
|
|
|
let modalOpen = false
|
2020-03-24 12:35:46 +01:00
|
|
|
let data = []
|
2020-03-16 19:54:48 +01:00
|
|
|
let headers = []
|
2020-03-24 12:35:46 +01:00
|
|
|
let views = []
|
2020-03-22 10:21:18 +01:00
|
|
|
let currentPage = 0
|
2020-03-12 15:23:29 +01:00
|
|
|
|
2020-03-24 12:35:46 +01:00
|
|
|
$: views = $backendUiStore.selectedRecord
|
|
|
|
? childViewsForRecord($store.hierarchy)
|
|
|
|
: $store.hierarchy.indexes
|
|
|
|
|
2020-03-16 19:54:48 +01:00
|
|
|
$: currentAppInfo = {
|
|
|
|
appname: $store.appname,
|
2020-03-23 11:43:34 +01:00
|
|
|
instanceId: $backendUiStore.selectedDatabase.id,
|
2020-03-16 19:54:48 +01:00
|
|
|
}
|
2020-03-24 12:35:46 +01:00
|
|
|
|
|
|
|
$: fetchRecordsForView(
|
|
|
|
$backendUiStore.selectedView,
|
|
|
|
$backendUiStore.selectedDatabase
|
|
|
|
).then(records => {
|
2020-03-25 11:59:47 +01:00
|
|
|
data = records || []
|
2020-03-25 17:59:32 +01:00
|
|
|
headers = hideInternalHeaders($backendUiStore.selectedView)
|
2020-03-24 12:35:46 +01:00
|
|
|
})
|
|
|
|
|
2020-03-25 11:59:47 +01:00
|
|
|
$: paginatedData = data.slice(
|
|
|
|
currentPage * ITEMS_PER_PAGE,
|
|
|
|
currentPage * ITEMS_PER_PAGE + ITEMS_PER_PAGE
|
|
|
|
)
|
|
|
|
|
2020-03-25 17:59:32 +01:00
|
|
|
const getSchema = getIndexSchema($store.hierarchy)
|
|
|
|
|
2020-04-06 16:38:33 +02:00
|
|
|
const childViewsForRecord = compose(flatten, map("indexes"), get("children"))
|
2020-03-12 15:23:29 +01:00
|
|
|
|
2020-03-25 17:59:32 +01:00
|
|
|
const hideInternalHeaders = compose(
|
|
|
|
remove(headerName => INTERNAL_HEADERS.includes(headerName)),
|
|
|
|
map(get("name")),
|
|
|
|
getSchema
|
|
|
|
)
|
2020-03-16 19:54:48 +01:00
|
|
|
|
2020-03-24 12:35:46 +01:00
|
|
|
async function fetchRecordsForView(view, instance) {
|
2020-03-26 18:39:42 +01:00
|
|
|
if (!view || !view.name) return
|
2020-03-25 11:59:47 +01:00
|
|
|
|
2020-03-24 12:35:46 +01:00
|
|
|
const viewName = $backendUiStore.selectedRecord
|
2020-03-26 15:31:56 +01:00
|
|
|
? `${$backendUiStore.selectedRecord.key}/${view.name}`
|
2020-03-24 12:35:46 +01:00
|
|
|
: view.name
|
2020-03-25 11:59:47 +01:00
|
|
|
|
|
|
|
return await api.fetchDataForView(viewName, {
|
2020-03-24 12:35:46 +01:00
|
|
|
appname: $store.appname,
|
|
|
|
instanceId: instance.id,
|
2020-03-20 19:47:01 +01:00
|
|
|
})
|
2020-03-16 19:54:48 +01:00
|
|
|
}
|
|
|
|
|
2020-03-23 15:15:09 +01:00
|
|
|
function drillIntoRecord(record) {
|
|
|
|
backendUiStore.update(state => {
|
2020-03-30 12:57:22 +02:00
|
|
|
state.breadcrumbs = [...state.breadcrumbs, record.type, record.id]
|
2020-03-24 12:35:46 +01:00
|
|
|
state.selectedRecord = record
|
2020-03-25 17:59:32 +01:00
|
|
|
state.selectedView = childViewsForRecord($store.hierarchy)[0]
|
2020-03-23 15:15:09 +01:00
|
|
|
return state
|
|
|
|
})
|
|
|
|
}
|
2020-03-25 11:59:47 +01:00
|
|
|
|
|
|
|
onMount(() => {
|
|
|
|
if (views.length) {
|
|
|
|
backendUiStore.actions.views.select(views[0])
|
|
|
|
}
|
|
|
|
})
|
2020-03-10 14:53:23 +01:00
|
|
|
</script>
|
|
|
|
|
2020-03-23 11:43:34 +01:00
|
|
|
<section>
|
|
|
|
<div class="table-controls">
|
2020-04-02 16:11:27 +02:00
|
|
|
<h2 class="title">
|
2020-03-31 13:16:03 +02:00
|
|
|
{takeRight(2, $backendUiStore.breadcrumbs).join(' / ')}
|
2020-04-02 16:11:27 +02:00
|
|
|
</h2>
|
2020-03-25 11:59:47 +01:00
|
|
|
<Select icon="ri-eye-line" bind:value={$backendUiStore.selectedView}>
|
2020-03-23 11:43:34 +01:00
|
|
|
{#each views as view}
|
2020-03-25 11:59:47 +01:00
|
|
|
<option value={view}>{view.name}</option>
|
2020-03-23 11:43:34 +01:00
|
|
|
{/each}
|
|
|
|
</Select>
|
|
|
|
</div>
|
|
|
|
<table class="uk-table">
|
|
|
|
<thead>
|
|
|
|
<tr>
|
|
|
|
<th>Edit</th>
|
|
|
|
{#each headers as header}
|
|
|
|
<th>{header}</th>
|
2020-03-10 17:06:30 +01:00
|
|
|
{/each}
|
2020-03-23 11:43:34 +01:00
|
|
|
</tr>
|
|
|
|
</thead>
|
|
|
|
<tbody>
|
2020-03-25 11:59:47 +01:00
|
|
|
{#if paginatedData.length === 0}
|
2020-03-23 11:43:34 +01:00
|
|
|
<div class="no-data">No Data.</div>
|
|
|
|
{/if}
|
2020-03-25 11:59:47 +01:00
|
|
|
{#each paginatedData as row}
|
2020-03-23 11:43:34 +01:00
|
|
|
<tr class="hoverable">
|
|
|
|
<td>
|
|
|
|
<div class="uk-inline">
|
|
|
|
<i class="ri-more-line" />
|
|
|
|
<div uk-dropdown="mode: click">
|
|
|
|
<ul class="uk-nav uk-dropdown-nav">
|
|
|
|
<li>
|
2020-03-23 15:15:09 +01:00
|
|
|
<div on:click={() => drillIntoRecord(row)}>View</div>
|
2020-03-23 11:43:34 +01:00
|
|
|
</li>
|
|
|
|
<li
|
|
|
|
on:click={() => {
|
2020-04-06 16:38:33 +02:00
|
|
|
editRecord(row)
|
2020-03-23 11:43:34 +01:00
|
|
|
}}>
|
|
|
|
<div>Edit</div>
|
|
|
|
</li>
|
|
|
|
<li>
|
|
|
|
<div
|
2020-03-16 19:54:48 +01:00
|
|
|
on:click={() => {
|
2020-04-06 16:44:53 +02:00
|
|
|
deleteRecord(row)
|
2020-03-16 19:54:48 +01:00
|
|
|
}}>
|
2020-03-23 11:43:34 +01:00
|
|
|
Delete
|
|
|
|
</div>
|
|
|
|
</li>
|
|
|
|
</ul>
|
2020-03-12 15:23:29 +01:00
|
|
|
</div>
|
2020-03-23 11:43:34 +01:00
|
|
|
</div>
|
|
|
|
</td>
|
|
|
|
{#each headers as header}
|
|
|
|
<td>{row[header]}</td>
|
|
|
|
{/each}
|
|
|
|
</tr>
|
|
|
|
{/each}
|
|
|
|
</tbody>
|
|
|
|
</table>
|
|
|
|
<TablePagination
|
2020-03-25 11:59:47 +01:00
|
|
|
{data}
|
2020-03-23 11:43:34 +01:00
|
|
|
bind:currentPage
|
|
|
|
pageItemCount={data.length}
|
2020-03-25 17:59:32 +01:00
|
|
|
{ITEMS_PER_PAGE} />
|
2020-03-23 11:43:34 +01:00
|
|
|
</section>
|
2020-03-10 14:53:23 +01:00
|
|
|
|
|
|
|
<style>
|
2020-04-02 16:11:27 +02:00
|
|
|
.title {
|
|
|
|
font-size: 24px;
|
|
|
|
font-weight: 600;
|
|
|
|
text-rendering: optimizeLegibility;
|
|
|
|
text-transform: capitalize;
|
|
|
|
}
|
|
|
|
|
|
|
|
.select {
|
|
|
|
background: white;
|
|
|
|
}
|
|
|
|
|
2020-03-10 14:53:23 +01:00
|
|
|
table {
|
|
|
|
border: 1px solid #ccc;
|
2020-03-10 17:06:30 +01:00
|
|
|
background: #fff;
|
2020-03-21 21:39:37 +01:00
|
|
|
border-radius: 3px;
|
2020-03-22 10:21:18 +01:00
|
|
|
border-collapse: collapse;
|
2020-03-10 14:53:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
thead {
|
2020-04-02 16:11:27 +02:00
|
|
|
background: #f9f9f9;
|
|
|
|
border: 1px solid #ccc;
|
2020-03-10 14:53:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
thead th {
|
|
|
|
color: var(--button-text);
|
|
|
|
text-transform: capitalize;
|
2020-03-10 17:06:30 +01:00
|
|
|
font-weight: 500;
|
2020-04-06 16:38:33 +02:00
|
|
|
font-size: 14px;
|
2020-04-02 16:11:27 +02:00
|
|
|
text-rendering: optimizeLegibility;
|
|
|
|
letter-spacing: 1px;
|
2020-03-10 14:53:23 +01:00
|
|
|
}
|
2020-03-10 17:06:30 +01:00
|
|
|
|
2020-03-20 19:47:01 +01:00
|
|
|
tbody tr {
|
2020-03-10 14:53:23 +01:00
|
|
|
border-bottom: 1px solid #ccc;
|
2020-03-20 19:47:01 +01:00
|
|
|
transition: 0.3s background-color;
|
2020-04-02 16:11:27 +02:00
|
|
|
color: var(--secondary100);
|
|
|
|
font-size: 14px;
|
2020-03-20 19:47:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
tbody tr:hover {
|
|
|
|
background: #fafafa;
|
2020-03-10 14:53:23 +01:00
|
|
|
}
|
2020-03-10 17:06:30 +01:00
|
|
|
|
|
|
|
.table-controls {
|
|
|
|
display: flex;
|
|
|
|
justify-content: space-between;
|
2020-04-02 16:11:27 +02:00
|
|
|
align-items: baseline;
|
|
|
|
margin-top: 10px;
|
2020-03-10 17:06:30 +01:00
|
|
|
}
|
2020-03-12 15:23:29 +01:00
|
|
|
|
2020-03-16 19:54:48 +01:00
|
|
|
.ri-more-line:hover,
|
|
|
|
.uk-dropdown-nav li:hover {
|
2020-03-12 15:23:29 +01:00
|
|
|
cursor: pointer;
|
|
|
|
}
|
2020-03-22 10:21:18 +01:00
|
|
|
|
|
|
|
.no-data {
|
|
|
|
padding: 20px;
|
|
|
|
}
|
2020-03-10 17:06:30 +01:00
|
|
|
</style>
|