redis: set ttl

This commit is contained in:
Jan Prochazka
2022-03-10 17:12:21 +01:00
parent 98a9859216
commit 3d72df424f
8 changed files with 235 additions and 33 deletions

View File

@@ -61,7 +61,7 @@
}
}
$: console.log(title, indentLevel);
// $: console.log(title, indentLevel);
</script>
<div

View File

@@ -1,41 +1,92 @@
<script lang="ts">
import { onMount } from 'svelte';
import { onMount, tick } from 'svelte';
import ScrollableTableControl from '../elements/ScrollableTableControl.svelte';
import { apiCall } from '../utility/api';
import createRef from '../utility/createRef';
export let conid;
export let database;
export let keyInfo;
export let onChangeSelected;
let rows = [];
let cursor = 0;
let isLoading = false;
let loadNextNeeded = false;
let isLoadedAll = false;
let selectedIndex;
const oldIndexRef = createRef(null);
async function loadRows() {
const res = await apiCall('database-connections/load-key-table-range', {
conid,
database,
key: keyInfo.key,
cursor,
count: 10,
});
rows = res.items;
async function loadNextRows() {
if (isLoading) {
// console.log('ALREADY LOADING');
loadNextNeeded = true;
return;
}
isLoading = true;
try {
const res = await apiCall('database-connections/load-key-table-range', {
conid,
database,
key: keyInfo.key,
cursor,
count: 10,
});
const newRows = [...rows];
for (const row of res.items) {
if (keyInfo.keyColumn && newRows.find(x => x[keyInfo.keyColumn] == row[keyInfo.keyColumn])) {
continue;
}
newRows.push({ rowNumber: newRows.length + 1, ...row });
}
rows = newRows;
cursor = res.cursor;
isLoadedAll = cursor == 0;
} finally {
isLoading = false;
}
if (loadNextNeeded) {
loadNextNeeded = false;
await tick();
loadNextRows();
}
}
$: {
if (onChangeSelected && rows[selectedIndex]) {
if (oldIndexRef.get() != selectedIndex) {
oldIndexRef.set(selectedIndex);
onChangeSelected(rows[selectedIndex]);
}
}
}
$: {
keyInfo;
}
onMount(() => {
loadRows();
loadNextRows();
});
</script>
<ScrollableTableControl
columns={[
keyInfo.tableColumns.map(fieldName => ({
fieldName,
header: fieldName,
{
fieldName: 'rowNumber',
header: 'num',
width: '60px',
},
...keyInfo.tableColumns.map(column => ({
fieldName: column.name,
header: column.name,
})),
]}
{rows}
onLoadNext={isLoadedAll ? null : loadNextRows}
selectable
singleLineRow
bind:selectedIndex
/>

View File

@@ -15,7 +15,7 @@
<script lang="ts">
import _ from 'lodash';
import { onMount } from 'svelte';
import { onDestroy, onMount } from 'svelte';
import keycodes from '../utility/keycodes';
import { createEventDispatcher } from 'svelte';
import resizeObserver from '../utility/resizeObserver';
@@ -27,6 +27,8 @@
export let selectedIndex = 0;
export let clickable = false;
export let disableFocusOutline = false;
export let onLoadNext = null;
export let singleLineRow = false;
export let domTable = undefined;
@@ -34,6 +36,36 @@
let headerHeight = 0;
let domBody;
let domLoadNext;
let observer;
function startObserver(dom) {
if (observer) {
// console.log('STOP OBSERVE');
observer.disconnect();
observer = null;
}
if (dom) {
// console.log('OBSERVE');
observer = new IntersectionObserver(entries => {
// console.log('ENTRIES', entries);
if (entries.find(x => x.isIntersecting)) {
// console.log('INVOKE LOAD NEXT');
onLoadNext();
}
});
observer.observe(dom);
}
}
$: startObserver(domLoadNext);
onDestroy(() => {
if (observer) {
observer.disconnect();
}
});
const dispatch = createEventDispatcher();
$: columnList = _.compact(_.flatten(columns));
@@ -86,6 +118,7 @@
bind:this={domTable}
class:selectable
class:disableFocusOutline
class:singleLineRow
on:keydown
tabindex={selectable ? -1 : undefined}
on:keydown={handleKeyDown}
@@ -163,6 +196,13 @@
{/each}
</tr>
{/each}
{#if onLoadNext}
{#key rows}
<tr>
<td colspan={columnList.length} bind:this={domLoadNext}> Loading next rows... </td>
</tr>
{/key}
{/if}
</tbody>
</table>
</div>
@@ -193,6 +233,11 @@
table tbody tr td {
overflow: hidden;
}
table.singleLineRow tbody tr td {
white-space: nowrap;
}
table tbody {
display: block;
overflow-y: scroll;

View File

@@ -19,6 +19,9 @@
import { getIconForRedisType } from 'dbgate-tools';
import TextField from '../forms/TextField.svelte';
import DbKeyTableControl from '../datagrid/DbKeyTableControl.svelte';
import { showModal } from '../modals/modalTools';
import InputTextModal from '../modals/InputTextModal.svelte';
import _ from 'lodash';
export let conid;
export let database;
@@ -27,8 +30,43 @@
export const activator = createActivator('DbKeyDetailTab', true);
let currentRow;
$: key = $activeDbKeysStore[`${conid}:${database}`];
let refreshToken = 0;
function handleChangeTtl(keyInfo) {
showModal(InputTextModal, {
value: keyInfo.ttl,
label: 'New TTL value (-1=key never expires)',
header: `Set TTL for key ${keyInfo.key}`,
onConfirm: async value => {
const ttl = parseInt(value);
if (_.isNumber(ttl)) {
if (ttl < 0) {
await apiCall('database-connections/call-method', {
conid,
database,
method: 'persist',
args: [keyInfo.key],
});
} else {
await apiCall('database-connections/call-method', {
conid,
database,
method: 'expire',
args: [keyInfo.key, ttl],
});
}
refresh();
}
},
});
}
function refresh() {
refreshToken += 1;
}
</script>
{#await apiCall('database-connections/load-key-info', { conid, database, key, refreshToken })}
@@ -36,28 +74,38 @@
{:then keyInfo}
<div class="container">
<div class="top-panel">
<FontIcon icon={getIconForRedisType(keyInfo.type)} padRight />
<div class="type">
<FontIcon icon={getIconForRedisType(keyInfo.type)} padRight />
{keyInfo.type}
</div>
<TextField value={key} readOnly />
{key}
TTL:{keyInfo.ttl}
<FormStyledButton
value="Refresh"
on:click={() => {
refreshToken += 1;
}}
/>
<div class="key-name">
<TextField value={key} readOnly />
</div>
<FormStyledButton value={`TTL:${keyInfo.ttl}`} on:click={() => handleChangeTtl(keyInfo)} />
<FormStyledButton value="Refresh" on:click={refresh} />
</div>
<div class="content">
{#if keyInfo.tableColumns}
<VerticalSplitter>
<svelte:fragment slot="1">
<DbKeyTableControl {conid} {database} {keyInfo} />
<DbKeyTableControl
{conid}
{database}
{keyInfo}
onChangeSelected={row => {
currentRow = row;
}}
/>
</svelte:fragment>
<svelte:fragment slot="2">PROPS</svelte:fragment>
<div slot="2" class="props">
{#each keyInfo.tableColumns as column}
<div class="colname">{column.name}</div>
<div class="colvalue">
<AceEditor readOnly value={currentRow && currentRow[column.name]} />
</div>
{/each}
</div>
</VerticalSplitter>
{:else}
<AceEditor readOnly value={keyInfo.value} />
@@ -80,9 +128,36 @@
.top-panel {
display: flex;
background: var(--theme-bg-2);
}
.type {
font-weight: bold;
margin-right: 10px;
align-self: center;
}
.props {
flex: 1;
display: flex;
flex-direction: column;
}
.colname {
margin: 10px;
}
.colvalue {
position: relative;
flex: 1;
}
.key-name {
flex-grow: 1;
display: flex;
}
.key-name :global(input) {
flex-grow: 1;
}
</style>