mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-27 20:46:00 +00:00
app object list
This commit is contained in:
@@ -28,6 +28,10 @@ body {
|
|||||||
background-color: var(--theme-bg-2);
|
background-color: var(--theme-bg-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon-invisible {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
/* html, body {
|
/* html, body {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
export let title;
|
export let title;
|
||||||
|
|
||||||
export let isBold = false;
|
export let isBold = false;
|
||||||
export let prefix = '';
|
|
||||||
export let isBusy = false;
|
export let isBusy = false;
|
||||||
export let statusIcon = undefined;
|
export let statusIcon = undefined;
|
||||||
export let statusTitle = undefined;
|
export let statusTitle = undefined;
|
||||||
@@ -15,7 +14,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="main" class:isBold draggable on:click use:contextMenu={menu}>
|
<div class="main" class:isBold draggable on:click use:contextMenu={menu}>
|
||||||
{prefix}
|
<slot name="prefix" />
|
||||||
{#if isBusy}
|
{#if isBusy}
|
||||||
<FontIcon icon="icon loading" />
|
<FontIcon icon="icon loading" />
|
||||||
{:else}
|
{:else}
|
||||||
|
|||||||
37
packages/web/src/appobj/AppObjectGroup.svelte
Normal file
37
packages/web/src/appobj/AppObjectGroup.svelte
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<script>
|
||||||
|
import AppObjectListItem from './AppObjectListItem.svelte';
|
||||||
|
|
||||||
|
export let group;
|
||||||
|
export let items;
|
||||||
|
export let module;
|
||||||
|
|
||||||
|
let isExpanded = true;
|
||||||
|
|
||||||
|
$: filtered = items.filter(x => x.isMatched);
|
||||||
|
$: countText = filtered.length < items.length ? `${filtered.length}/${items.length}` : `${items.length}`;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="group" on:click={() => (isExpanded = !isExpanded)}>
|
||||||
|
{group}
|
||||||
|
{items && `(${countText})`}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if isExpanded}
|
||||||
|
{#each filtered as item (module.extractKey(item.data))}
|
||||||
|
<AppObjectListItem {module} data={item.data} on:objectClick />
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.group {
|
||||||
|
user-select: none;
|
||||||
|
padding: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
white-space: nowrap;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group:hover {
|
||||||
|
background-color: var(--theme-bg-hover);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,10 +1,14 @@
|
|||||||
<script lang="ts">
|
<script>
|
||||||
|
import _ from 'lodash';
|
||||||
|
import AppObjectGroup from './AppObjectGroup.svelte';
|
||||||
|
|
||||||
import AppObjectListItem from './AppObjectListItem.svelte';
|
import AppObjectListItem from './AppObjectListItem.svelte';
|
||||||
|
|
||||||
export let list;
|
export let list;
|
||||||
export let module;
|
export let module;
|
||||||
export let subItemsComponent = undefined;
|
export let subItemsComponent = undefined;
|
||||||
export let expandOnClick = false;
|
export let expandOnClick = false;
|
||||||
|
export let isExpandable = undefined;
|
||||||
export let filter;
|
export let filter;
|
||||||
|
|
||||||
export let groupFunc = undefined;
|
export let groupFunc = undefined;
|
||||||
@@ -14,8 +18,27 @@
|
|||||||
if (matcher && !matcher(filter)) return false;
|
if (matcher && !matcher(filter)) return false;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$: listGrouped = groupFunc
|
||||||
|
? _.compact(
|
||||||
|
(list || []).map(data => {
|
||||||
|
const matcher = module.createMatcher && module.createMatcher(data);
|
||||||
|
const isMatched = matcher && !matcher(filter) ? false : true;
|
||||||
|
const group = groupFunc(data);
|
||||||
|
return { group, data, isMatched };
|
||||||
|
})
|
||||||
|
)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
$: groups = groupFunc ? _.groupBy(listGrouped, 'group') : null;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#each filtered as data}
|
{#if groupFunc}
|
||||||
<AppObjectListItem {module} {subItemsComponent} {expandOnClick} {data} on:objectClick />
|
{#each _.keys(groups) as group (group)}
|
||||||
|
<AppObjectGroup {group} {module} items={groups[group]} />
|
||||||
{/each}
|
{/each}
|
||||||
|
{:else}
|
||||||
|
{#each filtered as data (module.extractKey(data))}
|
||||||
|
<AppObjectListItem {module} {subItemsComponent} {expandOnClick} {data} {isExpandable} on:objectClick />
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
|
|||||||
@@ -1,20 +1,52 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import ExpandIcon from '../icons/ExpandIcon.svelte';
|
||||||
|
import { tick } from 'svelte';
|
||||||
|
|
||||||
export let module;
|
export let module;
|
||||||
export let data;
|
export let data;
|
||||||
export let subItemsComponent;
|
export let subItemsComponent;
|
||||||
export let expandOnClick;
|
export let expandOnClick;
|
||||||
|
export let isExpandable = undefined;
|
||||||
|
|
||||||
let isExpanded = false;
|
let isExpanded = false;
|
||||||
|
|
||||||
function handleExpand() {
|
async function handleExpand() {
|
||||||
if (subItemsComponent && expandOnClick) {
|
if (subItemsComponent && expandOnClick) {
|
||||||
|
await tick();
|
||||||
isExpanded = !isExpanded;
|
isExpanded = !isExpanded;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$: expandable = data && isExpandable && isExpandable(data);
|
||||||
|
|
||||||
|
$: if (!expandable && isExpanded) isExpanded = false;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
{#if subItemsComponent}
|
||||||
|
<svelte:component this={module.default} {data} on:click={handleExpand}>
|
||||||
|
<span class="expand-icon" slot="prefix">
|
||||||
|
{#if expandable}
|
||||||
|
<ExpandIcon {isExpanded} />
|
||||||
|
{:else}
|
||||||
|
<ExpandIcon isBlank />
|
||||||
|
{/if}
|
||||||
|
</span>
|
||||||
|
</svelte:component>
|
||||||
|
{:else}
|
||||||
<svelte:component this={module.default} {data} on:click={handleExpand} />
|
<svelte:component this={module.default} {data} on:click={handleExpand} />
|
||||||
|
{/if}
|
||||||
|
|
||||||
{#if isExpanded && subItemsComponent}
|
{#if isExpanded && subItemsComponent}
|
||||||
|
<div class="subitems">
|
||||||
<svelte:component this={subItemsComponent} {data} />
|
<svelte:component this={subItemsComponent} {data} />
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.expand-icon {
|
||||||
|
margin-right: 3px;
|
||||||
|
}
|
||||||
|
.subitems {
|
||||||
|
margin-left: 28px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -102,6 +102,8 @@
|
|||||||
statusTitle={statusTitle || engineStatusTitle}
|
statusTitle={statusTitle || engineStatusTitle}
|
||||||
{extInfo}
|
{extInfo}
|
||||||
menu={getContextMenu(data, $openedConnections)}
|
menu={getContextMenu(data, $openedConnections)}
|
||||||
on:click
|
|
||||||
on:click={() => ($openedConnections = _.uniq([...$openedConnections, data._id]))}
|
on:click={() => ($openedConnections = _.uniq([...$openedConnections, data._id]))}
|
||||||
/>
|
on:click
|
||||||
|
>
|
||||||
|
<slot name="prefix" slot="prefix" />
|
||||||
|
</AppObjectCore>
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
<script lang="ts" context="module">
|
||||||
|
export const extractKey = props => props.name;
|
||||||
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
|
<script lang="ts" context="module">
|
||||||
|
export const extractKey = ({ schemaName, pureName }) => (schemaName ? `${schemaName}.${pureName}` : pureName);
|
||||||
|
export const createMatcher = ({ pureName }) => filter => filterName(filter, pureName);
|
||||||
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import AppObjectCore from './AppObjectCore.svelte';
|
import AppObjectCore from './AppObjectCore.svelte';
|
||||||
import { currentDatabase, openedConnections } from '../stores';
|
import { currentDatabase, openedConnections } from '../stores';
|
||||||
import openNewTab from '../utility/openNewTab';
|
import openNewTab from '../utility/openNewTab';
|
||||||
|
import { filterName } from 'dbgate-datalib';
|
||||||
|
|
||||||
export let commonProps;
|
export let commonProps;
|
||||||
export let data;
|
export let data;
|
||||||
|
|||||||
12
packages/web/src/icons/ExpandIcon.svelte
Normal file
12
packages/web/src/icons/ExpandIcon.svelte
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<script>
|
||||||
|
import FontIcon from './FontIcon.svelte';
|
||||||
|
|
||||||
|
export let isBlank = false;
|
||||||
|
export let isExpanded = false;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if isBlank}
|
||||||
|
<FontIcon icon="icon invisible-box" {...$$props} />
|
||||||
|
{:else}
|
||||||
|
<FontIcon icon={isExpanded ? 'icon minus-box' : 'icon plus-box'} {...$$props} />
|
||||||
|
{/if}
|
||||||
@@ -102,4 +102,4 @@
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<span class={iconNames[icon] || icon} {title} />
|
<span class={iconNames[icon] || icon} {title} on:click />
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
import AppObjectList from '../appobj/AppObjectList.svelte';
|
import AppObjectList from '../appobj/AppObjectList.svelte';
|
||||||
import * as connectionAppObject from '../appobj/ConnectionAppObject.svelte';
|
import * as connectionAppObject from '../appobj/ConnectionAppObject.svelte';
|
||||||
import SubDatabaseList from '../appobj/SubDatabaseList.svelte';
|
import SubDatabaseList from '../appobj/SubDatabaseList.svelte';
|
||||||
|
import { openedConnections } from '../stores';
|
||||||
|
|
||||||
const connections = useConnectionList();
|
const connections = useConnectionList();
|
||||||
const serverStatus = useServerStatus();
|
const serverStatus = useServerStatus();
|
||||||
@@ -30,6 +31,7 @@
|
|||||||
module={connectionAppObject}
|
module={connectionAppObject}
|
||||||
subItemsComponent={SubDatabaseList}
|
subItemsComponent={SubDatabaseList}
|
||||||
expandOnClick
|
expandOnClick
|
||||||
|
isExpandable={data => $openedConnections.includes(data._id)}
|
||||||
{filter}
|
{filter}
|
||||||
/>
|
/>
|
||||||
</WidgetsInnerContainer>
|
</WidgetsInnerContainer>
|
||||||
|
|||||||
@@ -12,6 +12,8 @@
|
|||||||
export let conid;
|
export let conid;
|
||||||
export let database;
|
export let database;
|
||||||
|
|
||||||
|
let filter = '';
|
||||||
|
|
||||||
$: objects = useDatabaseInfo({ conid, database });
|
$: objects = useDatabaseInfo({ conid, database });
|
||||||
$: status = useDatabaseStatus({ conid, database });
|
$: status = useDatabaseStatus({ conid, database });
|
||||||
|
|
||||||
@@ -26,9 +28,14 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<SearchBoxWrapper>
|
<SearchBoxWrapper>
|
||||||
<SearchInput placeholder="Search connection" />
|
<SearchInput placeholder="Search connection" bind:value={filter} />
|
||||||
<InlineButton>Refresh</InlineButton>
|
<InlineButton>Refresh</InlineButton>
|
||||||
</SearchBoxWrapper>
|
</SearchBoxWrapper>
|
||||||
<WidgetsInnerContainer>
|
<WidgetsInnerContainer>
|
||||||
<AppObjectList list={objectList.map(x => ({ ...x, conid, database }))} module={databaseObjectAppObject} />
|
<AppObjectList
|
||||||
|
list={objectList.map(x => ({ ...x, conid, database }))}
|
||||||
|
module={databaseObjectAppObject}
|
||||||
|
groupFunc={data => _.startCase(data.objectTypeField)}
|
||||||
|
{filter}
|
||||||
|
/>
|
||||||
</WidgetsInnerContainer>
|
</WidgetsInnerContainer>
|
||||||
|
|||||||
Reference in New Issue
Block a user