rune-lab 0.0.7 โ 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -25
- package/dist/components/api/RLApiInterface.svelte +18 -12
- package/dist/components/api/RLApiInterface.svelte.d.ts +4 -6
- package/dist/components/common/RLPripertyTable.svelte +107 -0
- package/dist/components/common/RLPripertyTable.svelte.d.ts +44 -0
- package/dist/components/dataview/RLDetailRow.svelte +61 -0
- package/dist/components/dataview/RLDetailRow.svelte.d.ts +20 -0
- package/dist/components/dataview/RLMetadataList.svelte +53 -0
- package/dist/components/dataview/RLMetadataList.svelte.d.ts +23 -0
- package/dist/components/dataview/RLMetadataTable.svelte +1 -4
- package/dist/components/explorer/RLEnumDisplay.svelte +34 -0
- package/dist/components/explorer/RLEnumDisplay.svelte.d.ts +7 -0
- package/dist/components/explorer/RLFunctionDisplay.svelte +64 -0
- package/dist/components/explorer/RLFunctionDisplay.svelte.d.ts +13 -0
- package/dist/components/explorer/RLSchemaExplorer.svelte +204 -319
- package/dist/components/explorer/RLTableDisplay.svelte +48 -0
- package/dist/components/explorer/RLTableDisplay.svelte.d.ts +16 -0
- package/dist/components/explorer/RLViewDisplay.svelte +46 -0
- package/dist/components/explorer/RLViewDisplay.svelte.d.ts +15 -0
- package/dist/components/form/RLFilterForm.svelte +1 -13
- package/dist/components/form/RLFunctionForm.svelte +2 -13
- package/dist/components/form/RLResourceForm.svelte +1 -13
- package/dist/components/stores/explorer.svelte.d.ts +59 -0
- package/dist/mod.d.ts +2 -0
- package/dist/mod.js +2 -0
- package/dist/tools/form-helpers.d.ts +23 -0
- package/dist/tools/form-helpers.js +51 -0
- package/dist/tools/schema-transformer.d.ts +5 -0
- package/dist/tools/schema-transformer.js +131 -0
- package/dist/types/api.d.ts +1 -0
- package/dist/types/api.js +1 -0
- package/dist/types/explorer.d.ts +1 -0
- package/dist/types/explorer.js +1 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<h1 align="center">
|
|
2
|
-
<img src="https://raw.githubusercontent.com/Yrrrrrf/rune-lab/main/static/rune.png" alt="Rune Lab Icon" width="128" height="128" description="
|
|
2
|
+
<img src="https://raw.githubusercontent.com/Yrrrrrf/rune-lab/main/static/rune.png" alt="Rune Lab Icon" width="128" height="128" description="Icon representing the Svelte Runes system">
|
|
3
3
|
<div align="center">Rune Lab</div>
|
|
4
4
|
</h1>
|
|
5
5
|
|
|
@@ -14,48 +14,61 @@
|
|
|
14
14
|
|
|
15
15
|
## Overview
|
|
16
16
|
|
|
17
|
-
Rune Lab is
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
**Rune Lab** is your modern toolkit for crafting stunning, reactive web applications with
|
|
18
|
+
**Svelte 5**. Harnessing the power of Svelte's new **Runes** system, Rune Lab offers a suite of
|
|
19
|
+
elegant UI components designed for seamless data handling and beautiful theming.
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
It's built to integrate effortlessly with your data sources, especially shining when connected
|
|
22
|
+
to the [prism-py](https://github.com/Yrrrrrf/prism-py) and
|
|
23
|
+
[prism-ts](https://github.com/Yrrrrrf/prism-ts) ecosystem for end-to-end type-safe API
|
|
24
|
+
interactions.
|
|
22
25
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
|
|
26
|
+
## Key Features
|
|
27
|
+
|
|
28
|
+
- **โจ Svelte 5 Runes Core:** Experience fine-grained reactivity and cleaner component logic.
|
|
29
|
+
- **๐จ Dynamic Theming:** Powered by DaisyUI & Tailwind CSS for extensive customization and
|
|
30
|
+
out-of-the-box themes.
|
|
31
|
+
- **๐ TypeScript First:** Robust type-safety for a confident and productive development
|
|
32
|
+
workflow.
|
|
33
|
+
- **๐ Data-Aware Components:** Tools and components built to handle and visualize complex data.
|
|
34
|
+
- **๐ฐ๏ธ Interactive Schema Explorer:** A standout feature! Visually explore and interact with
|
|
35
|
+
database schemas exposed by `prism-py` APIs directly within your Svelte application. Test CRUD
|
|
36
|
+
operations, execute functions, and understand your data structure like never before.
|
|
37
|
+
- **๐ Smart API Integration:** Includes `apiStore` (using `prism-ts`) for easy and type-safe
|
|
38
|
+
connection to backend APIs.
|
|
39
|
+
- **๐ฆ Lightweight Core:** Designed to be lean, with optional integrations.
|
|
40
|
+
- **๐ฆ Universal Access:** Available on JSR (for Deno) and NPM (for Node.js/Bun/Yarn).
|
|
41
|
+
|
|
42
|
+
## The Prism Ecosystem Advantage
|
|
43
|
+
|
|
44
|
+
Rune Lab is designed to be a perfect companion to the Prism ecosystem:
|
|
45
|
+
|
|
46
|
+
- **[prism-py](https://github.com/Yrrrrrf/prism-py):** Automatically generates REST APIs from
|
|
47
|
+
your database schema.
|
|
48
|
+
- **[prism-ts](https://github.com/Yrrrrrf/prism-ts):** A TypeScript client that consumes these
|
|
49
|
+
APIs with full type-safety.
|
|
50
|
+
|
|
51
|
+
When used together, Rune Lab's API integration tools (like the `apiStore` and
|
|
52
|
+
`RLSchemaExplorer`) provide a remarkably streamlined and type-safe path from your backend data
|
|
53
|
+
to your frontend UI.
|
|
30
54
|
|
|
31
55
|
## Installation
|
|
32
56
|
|
|
33
|
-
### Using Deno / JSR
|
|
57
|
+
### Using Deno / [JSR](https://jsr.io/@yrrrrrf/rune-lab)
|
|
34
58
|
|
|
35
59
|
```bash
|
|
36
60
|
# Add to your Deno project
|
|
37
61
|
deno add @yrrrrrf/rune-lab
|
|
38
62
|
```
|
|
39
63
|
|
|
40
|
-
### Using NPM / Bun / Yarn
|
|
64
|
+
### Using [NPM](https://www.npmjs.com/package/rune-lab) / Bun / Yarn
|
|
41
65
|
|
|
42
66
|
```bash
|
|
43
|
-
# NPM
|
|
44
67
|
npm install rune-lab
|
|
45
|
-
|
|
46
|
-
# Bun
|
|
47
68
|
bun add rune-lab
|
|
48
|
-
|
|
49
|
-
# Yarn
|
|
50
69
|
yarn add rune-lab
|
|
51
70
|
```
|
|
52
71
|
|
|
53
72
|
## License
|
|
54
73
|
|
|
55
74
|
MIT License - See [LICENSE](LICENSE) for details.
|
|
56
|
-
|
|
57
|
-
---
|
|
58
|
-
|
|
59
|
-
<div align="center">
|
|
60
|
-
Built with โค๏ธ using Svelte 5 and Deno
|
|
61
|
-
</div>
|
|
@@ -1,46 +1,52 @@
|
|
|
1
1
|
<!-- src/lib/components/api/RLApiInterface.svelte -->
|
|
2
2
|
<script lang="ts">
|
|
3
|
-
import type { ColumnMetadata } from '@yrrrrrf/prism-ts';
|
|
4
|
-
|
|
3
|
+
import type { ColumnMetadata as PrismColumnMetadata } from '@yrrrrrf/prism-ts';
|
|
4
|
+
// Import RLApiInterfaceActionParams from YOUR definition in the explorer store
|
|
5
|
+
import type { RLApiInterfaceActionParams } from '../stores/explorer.svelte.ts';
|
|
6
|
+
|
|
7
|
+
// For convenience within this component, you can extract the operation type.
|
|
8
|
+
// This is NOT redefining it; it's creating a local alias to a part of an imported type.
|
|
9
|
+
type LocalAPIOperation = RLApiInterfaceActionParams['operation'];
|
|
5
10
|
|
|
6
11
|
let {
|
|
7
12
|
schemaName,
|
|
8
13
|
resourceName,
|
|
9
14
|
resourceType,
|
|
10
15
|
columns,
|
|
11
|
-
onOpenModal
|
|
16
|
+
onOpenModal
|
|
12
17
|
} = $props<{
|
|
13
18
|
schemaName: string;
|
|
14
19
|
resourceName: string;
|
|
15
|
-
resourceType: 'table' | 'view' | 'function';
|
|
16
|
-
columns:
|
|
17
|
-
onOpenModal: (params:
|
|
20
|
+
resourceType: 'table' | 'view' | 'function';
|
|
21
|
+
columns: PrismColumnMetadata[]; // This prop is fine if it's what the component receives
|
|
22
|
+
onOpenModal: (params: RLApiInterfaceActionParams) => void; // Uses your imported interface
|
|
18
23
|
}>();
|
|
19
24
|
|
|
20
|
-
|
|
25
|
+
// Use the local alias or RLApiInterfaceActionParams['operation']
|
|
26
|
+
function getAllowedOps(type: 'table' | 'view' | 'function'): LocalAPIOperation[] {
|
|
21
27
|
if (type === 'table') return ['GET', 'POST', 'PUT', 'DELETE'];
|
|
22
28
|
if (type === 'view') return ['GET'];
|
|
23
|
-
if (type === 'function') return ['POST'];
|
|
29
|
+
if (type === 'function') return ['POST'];
|
|
24
30
|
return [];
|
|
25
31
|
}
|
|
26
32
|
|
|
27
|
-
const operationDetails: Record<
|
|
33
|
+
const operationDetails: Record<LocalAPIOperation, { label: string, class: string }> = {
|
|
28
34
|
GET: { label: 'GET', class: 'btn-info' },
|
|
29
35
|
POST: { label: 'POST', class: 'btn-success' },
|
|
30
36
|
PUT: { label: 'PUT', class: 'btn-warning' },
|
|
31
37
|
DELETE: { label: 'DELETE', class: 'btn-error' },
|
|
32
38
|
};
|
|
33
39
|
|
|
34
|
-
function handleOperationClick(operation:
|
|
40
|
+
function handleOperationClick(operation: LocalAPIOperation) {
|
|
41
|
+
// Construct the object that matches RLApiInterfaceActionParams
|
|
35
42
|
onOpenModal({ operation });
|
|
36
43
|
}
|
|
37
|
-
|
|
38
44
|
</script>
|
|
39
45
|
|
|
40
46
|
<div class="flex flex-wrap gap-2 my-2">
|
|
41
47
|
{#each getAllowedOps(resourceType) as operation}
|
|
42
48
|
{@const detail = operationDetails[operation]}
|
|
43
|
-
{#if detail}
|
|
49
|
+
{#if detail}
|
|
44
50
|
<button
|
|
45
51
|
class="btn btn-sm {detail.class}"
|
|
46
52
|
onclick={() => handleOperationClick(operation)}
|
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import type { ColumnMetadata } from '@yrrrrrf/prism-ts';
|
|
2
|
-
type
|
|
1
|
+
import type { ColumnMetadata as PrismColumnMetadata } from '@yrrrrrf/prism-ts';
|
|
2
|
+
import type { RLApiInterfaceActionParams } from '../stores/explorer.svelte.ts';
|
|
3
3
|
type $$ComponentProps = {
|
|
4
4
|
schemaName: string;
|
|
5
5
|
resourceName: string;
|
|
6
6
|
resourceType: 'table' | 'view' | 'function';
|
|
7
|
-
columns:
|
|
8
|
-
onOpenModal: (params:
|
|
9
|
-
operation: APIOperation;
|
|
10
|
-
}) => void;
|
|
7
|
+
columns: PrismColumnMetadata[];
|
|
8
|
+
onOpenModal: (params: RLApiInterfaceActionParams) => void;
|
|
11
9
|
};
|
|
12
10
|
declare const RlApiInterface: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
13
11
|
type RlApiInterface = ReturnType<typeof RlApiInterface>;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
<!-- src/lib/components/common/RLPropertyTable.svelte (example structure) -->
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
import type { RLEnumMetadata, RLColumnReference } from '../stores/explorer.svelte';
|
|
4
|
+
|
|
5
|
+
export interface RLPropertyItem {
|
|
6
|
+
name: string;
|
|
7
|
+
type?: string;
|
|
8
|
+
nullable?: boolean;
|
|
9
|
+
isPrimaryKey?: boolean;
|
|
10
|
+
references?: RLColumnReference;
|
|
11
|
+
isEnum?: boolean;
|
|
12
|
+
mode?: string; // For function params
|
|
13
|
+
hasDefault?: boolean;
|
|
14
|
+
defaultValue?: string | null;
|
|
15
|
+
// Any other properties needed to render details
|
|
16
|
+
_rawItem?: any; // Optional: pass the original item if needed by slot
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let {
|
|
20
|
+
items,
|
|
21
|
+
title = '',
|
|
22
|
+
nameHeader = "Name",
|
|
23
|
+
detailHeader = "Details",
|
|
24
|
+
enumsInSchema, // Pass this if needed for enum badge clicks from here
|
|
25
|
+
onFkClick,
|
|
26
|
+
onEnumClick,
|
|
27
|
+
} = $props<{
|
|
28
|
+
items: RLPropertyItem[];
|
|
29
|
+
title?: string;
|
|
30
|
+
nameHeader?: string;
|
|
31
|
+
detailHeader?: string;
|
|
32
|
+
enumsInSchema?: Record<string, RLEnumMetadata>; // For resolving enum names if items only have partial enum info
|
|
33
|
+
onFkClick?: (ref: RLColumnReference) => void;
|
|
34
|
+
onEnumClick?: (enumData: RLEnumMetadata) => void;
|
|
35
|
+
}>();
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<div class="card bg-base-100 shadow-sm overflow-hidden my-2">
|
|
39
|
+
{#if title}
|
|
40
|
+
<div class="card-title p-3 text-sm font-semibold bg-base-200/50">{title}</div>
|
|
41
|
+
{/if}
|
|
42
|
+
<div class="card-body p-0">
|
|
43
|
+
{#if items && items.length > 0}
|
|
44
|
+
<div class="overflow-x-auto">
|
|
45
|
+
<table class="table table-sm w-full">
|
|
46
|
+
<thead>
|
|
47
|
+
<tr>
|
|
48
|
+
<th class="w-2/5 pl-4">{nameHeader}</th>
|
|
49
|
+
{#if detailHeader} <th class="w-3/5 pr-4">{detailHeader}</th> {/if}
|
|
50
|
+
</tr>
|
|
51
|
+
</thead>
|
|
52
|
+
<tbody>
|
|
53
|
+
{#each items as item (item.name)}
|
|
54
|
+
<tr class="hover">
|
|
55
|
+
<td class="align-top py-2 pl-4">
|
|
56
|
+
<div class="flex items-baseline">
|
|
57
|
+
<span class="font-medium">{item.name}</span>
|
|
58
|
+
{#if item.nullable === false && item.type && !item.type.toLowerCase().includes('bool')} <!-- Nullability for non-booleans -->
|
|
59
|
+
<span class="text-error ml-1 select-none" title="Required field">*</span>
|
|
60
|
+
{/if}
|
|
61
|
+
</div>
|
|
62
|
+
{#if item.type && detailHeader} <!-- Only show type if details are shown and type exists -->
|
|
63
|
+
<div class="font-mono text-xs text-base-content/60 italic mt-0.5">{item.type}</div>
|
|
64
|
+
{/if}
|
|
65
|
+
</td>
|
|
66
|
+
{#if detailHeader}
|
|
67
|
+
<td class="align-top py-2 pr-4 space-x-1.5">
|
|
68
|
+
{#if $$slots.detail}
|
|
69
|
+
<slot name="detail" itemData={item}></slot>
|
|
70
|
+
{:else}
|
|
71
|
+
<!-- Default detail rendering -->
|
|
72
|
+
{#if item.isPrimaryKey} <span class="badge badge-accent badge-xs font-semibold">PK</span> {/if}
|
|
73
|
+
{#if item.references}
|
|
74
|
+
<span class="badge badge-secondary badge-xs">FK</span>
|
|
75
|
+
<button class="link link-hover text-xs font-mono !text-info normal-case"
|
|
76
|
+
onclick={() => onFkClick && onFkClick(item.references!)}
|
|
77
|
+
title="Navigate to {item.references.schema}.{item.references.table}.{item.references.column}">
|
|
78
|
+
{item.references.schema}.{item.references.table}.{item.references.column}
|
|
79
|
+
</button>
|
|
80
|
+
{/if}
|
|
81
|
+
{#if item.isEnum && enumsInSchema && enumsInSchema[item.name + '_enum'] /* Crude example of finding enum */}
|
|
82
|
+
{@const enumMeta = enumsInSchema[item.name + '_enum']}
|
|
83
|
+
<button class="badge badge-warning badge-xs hover:shadow-md transition-shadow normal-case"
|
|
84
|
+
onclick={() => onEnumClick && onEnumClick(enumMeta)}
|
|
85
|
+
title="Enum: {enumMeta.name}">
|
|
86
|
+
<span class="mr-1 opacity-70">Enum:</span>{enumMeta.name}
|
|
87
|
+
</button>
|
|
88
|
+
{:else if item.isEnum}
|
|
89
|
+
<span class="badge badge-ghost badge-xs">Enum</span>
|
|
90
|
+
{/if}
|
|
91
|
+
{#if item.mode} <span class="badge badge-info badge-xs">{item.mode}</span> {/if}
|
|
92
|
+
{#if item.hasDefault} <span class="badge badge-outline badge-xs" title="Default: {item.defaultValue}">Has Default</span> {/if}
|
|
93
|
+
{/if}
|
|
94
|
+
</td>
|
|
95
|
+
{/if}
|
|
96
|
+
</tr>
|
|
97
|
+
{/each}
|
|
98
|
+
</tbody>
|
|
99
|
+
</table>
|
|
100
|
+
</div>
|
|
101
|
+
{:else}
|
|
102
|
+
<div class="p-4 text-center text-neutral-content/70">
|
|
103
|
+
No items to display.
|
|
104
|
+
</div>
|
|
105
|
+
{/if}
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { RLEnumMetadata, RLColumnReference } from '../stores/explorer.svelte';
|
|
2
|
+
export interface RLPropertyItem {
|
|
3
|
+
name: string;
|
|
4
|
+
type?: string;
|
|
5
|
+
nullable?: boolean;
|
|
6
|
+
isPrimaryKey?: boolean;
|
|
7
|
+
references?: RLColumnReference;
|
|
8
|
+
isEnum?: boolean;
|
|
9
|
+
mode?: string;
|
|
10
|
+
hasDefault?: boolean;
|
|
11
|
+
defaultValue?: string | null;
|
|
12
|
+
_rawItem?: any;
|
|
13
|
+
}
|
|
14
|
+
type $$ComponentProps = {
|
|
15
|
+
items: RLPropertyItem[];
|
|
16
|
+
title?: string;
|
|
17
|
+
nameHeader?: string;
|
|
18
|
+
detailHeader?: string;
|
|
19
|
+
enumsInSchema?: Record<string, RLEnumMetadata>;
|
|
20
|
+
onFkClick?: (ref: RLColumnReference) => void;
|
|
21
|
+
onEnumClick?: (enumData: RLEnumMetadata) => void;
|
|
22
|
+
};
|
|
23
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
24
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
25
|
+
$$bindings?: Bindings;
|
|
26
|
+
} & Exports;
|
|
27
|
+
(internal: unknown, props: Props & {
|
|
28
|
+
$$events?: Events;
|
|
29
|
+
$$slots?: Slots;
|
|
30
|
+
}): Exports & {
|
|
31
|
+
$set?: any;
|
|
32
|
+
$on?: any;
|
|
33
|
+
};
|
|
34
|
+
z_$$bindings?: Bindings;
|
|
35
|
+
}
|
|
36
|
+
declare const RlPripertyTable: $$__sveltets_2_IsomorphicComponent<$$ComponentProps, {
|
|
37
|
+
[evt: string]: CustomEvent<any>;
|
|
38
|
+
}, {
|
|
39
|
+
detail: {
|
|
40
|
+
itemData: unknown;
|
|
41
|
+
};
|
|
42
|
+
}, {}, "">;
|
|
43
|
+
type RlPripertyTable = InstanceType<typeof RlPripertyTable>;
|
|
44
|
+
export default RlPripertyTable;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
<!-- src/lib/components/dataview/RLDetailRow.svelte -->
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
// No specific types needed from explorer.ts for these direct props.
|
|
4
|
+
// This component is highly generic.
|
|
5
|
+
|
|
6
|
+
type DetailAction = {
|
|
7
|
+
text: string;
|
|
8
|
+
class?: string;
|
|
9
|
+
onClick?: (event: MouseEvent) => void;
|
|
10
|
+
title?: string; // For tooltip on the badge/button
|
|
11
|
+
isLink?: boolean; // To render as a link-styled button
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
let {
|
|
15
|
+
name,
|
|
16
|
+
typeInfo = undefined,
|
|
17
|
+
details = [],
|
|
18
|
+
required = false,
|
|
19
|
+
description = undefined,
|
|
20
|
+
nameClass = 'font-medium',
|
|
21
|
+
typeInfoClass = 'font-mono text-xs text-base-content/60 italic mt-0.5',
|
|
22
|
+
containerClass = 'flex justify-between items-baseline py-1.5 hover:bg-base-content/5 px-1 rounded group',
|
|
23
|
+
} = $props<{
|
|
24
|
+
name: string;
|
|
25
|
+
typeInfo?: string;
|
|
26
|
+
details?: DetailAction[];
|
|
27
|
+
required?: boolean;
|
|
28
|
+
description?: string;
|
|
29
|
+
nameClass?: string;
|
|
30
|
+
typeInfoClass?: string;
|
|
31
|
+
containerClass?: string;
|
|
32
|
+
}>();
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<div class="{containerClass}" title={description}>
|
|
36
|
+
<div class="flex-grow overflow-hidden pr-2">
|
|
37
|
+
<span class="{nameClass}">{name}</span>
|
|
38
|
+
{#if required}
|
|
39
|
+
<span class="text-error ml-1 select-none" title="Required field">*</span>
|
|
40
|
+
{/if}
|
|
41
|
+
{#if typeInfo}
|
|
42
|
+
<div class="{typeInfoClass} truncate" title={typeInfo}>{typeInfo}</div>
|
|
43
|
+
{/if}
|
|
44
|
+
</div>
|
|
45
|
+
{#if details.length > 0}
|
|
46
|
+
<div class="flex-shrink-0 space-x-1.5 flex items-center">
|
|
47
|
+
{#each details as detailItem}
|
|
48
|
+
<button
|
|
49
|
+
class="badge badge-sm whitespace-nowrap {detailItem.class || 'badge-ghost'}
|
|
50
|
+
{detailItem.isLink ? 'link link-hover !text-info normal-case font-mono' : ''}
|
|
51
|
+
disabled:opacity-50"
|
|
52
|
+
onclick={detailItem.onClick}
|
|
53
|
+
title={detailItem.title || detailItem.text}
|
|
54
|
+
disabled={!detailItem.onClick && !detailItem.isLink}
|
|
55
|
+
>
|
|
56
|
+
{@html detailItem.text} <!-- Use @html if text might contain simple entities like โ -->
|
|
57
|
+
</button>
|
|
58
|
+
{/each}
|
|
59
|
+
</div>
|
|
60
|
+
{/if}
|
|
61
|
+
</div>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
type DetailAction = {
|
|
2
|
+
text: string;
|
|
3
|
+
class?: string;
|
|
4
|
+
onClick?: (event: MouseEvent) => void;
|
|
5
|
+
title?: string;
|
|
6
|
+
isLink?: boolean;
|
|
7
|
+
};
|
|
8
|
+
type $$ComponentProps = {
|
|
9
|
+
name: string;
|
|
10
|
+
typeInfo?: string;
|
|
11
|
+
details?: DetailAction[];
|
|
12
|
+
required?: boolean;
|
|
13
|
+
description?: string;
|
|
14
|
+
nameClass?: string;
|
|
15
|
+
typeInfoClass?: string;
|
|
16
|
+
containerClass?: string;
|
|
17
|
+
};
|
|
18
|
+
declare const RlDetailRow: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
19
|
+
type RlDetailRow = ReturnType<typeof RlDetailRow>;
|
|
20
|
+
export default RlDetailRow;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<!-- src/lib/components/dataview/RLMetadataList.svelte -->
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
import RLDetailRow from './RLDetailRow.svelte';
|
|
4
|
+
|
|
5
|
+
type DetailActionForList = { // Prop structure for items passed to RLDetailRow
|
|
6
|
+
text: string;
|
|
7
|
+
class?: string;
|
|
8
|
+
onClick?: (event: MouseEvent) => void;
|
|
9
|
+
title?: string;
|
|
10
|
+
isLink?: boolean;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export interface RLMetadataListItem {
|
|
14
|
+
name: string;
|
|
15
|
+
typeInfo?: string;
|
|
16
|
+
details?: DetailActionForList[];
|
|
17
|
+
required?: boolean;
|
|
18
|
+
description?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let {
|
|
22
|
+
title = undefined,
|
|
23
|
+
items = [],
|
|
24
|
+
listClass = 'divide-y divide-base-300/50',
|
|
25
|
+
emptyText = 'None.',
|
|
26
|
+
} = $props<{
|
|
27
|
+
title?: string;
|
|
28
|
+
items: RLMetadataListItem[];
|
|
29
|
+
listClass?: string;
|
|
30
|
+
emptyText?: string;
|
|
31
|
+
}>();
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<div>
|
|
35
|
+
{#if title}
|
|
36
|
+
<h4 class="font-semibold text-sm mb-1 mt-2 opacity-80">{title}</h4>
|
|
37
|
+
{/if}
|
|
38
|
+
{#if items.length > 0}
|
|
39
|
+
<div class="{listClass} border-t border-b border-base-300/30 -mx-1">
|
|
40
|
+
{#each items as item (item.name) }
|
|
41
|
+
<RLDetailRow
|
|
42
|
+
name={item.name}
|
|
43
|
+
typeInfo={item.typeInfo}
|
|
44
|
+
details={item.details}
|
|
45
|
+
required={item.required}
|
|
46
|
+
description={item.description}
|
|
47
|
+
/>
|
|
48
|
+
{/each}
|
|
49
|
+
</div>
|
|
50
|
+
{:else}
|
|
51
|
+
<p class="text-xs text-base-content/50 italic py-1.5 px-1">{emptyText}</p>
|
|
52
|
+
{/if}
|
|
53
|
+
</div>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
type DetailActionForList = {
|
|
2
|
+
text: string;
|
|
3
|
+
class?: string;
|
|
4
|
+
onClick?: (event: MouseEvent) => void;
|
|
5
|
+
title?: string;
|
|
6
|
+
isLink?: boolean;
|
|
7
|
+
};
|
|
8
|
+
export interface RLMetadataListItem {
|
|
9
|
+
name: string;
|
|
10
|
+
typeInfo?: string;
|
|
11
|
+
details?: DetailActionForList[];
|
|
12
|
+
required?: boolean;
|
|
13
|
+
description?: string;
|
|
14
|
+
}
|
|
15
|
+
type $$ComponentProps = {
|
|
16
|
+
title?: string;
|
|
17
|
+
items: RLMetadataListItem[];
|
|
18
|
+
listClass?: string;
|
|
19
|
+
emptyText?: string;
|
|
20
|
+
};
|
|
21
|
+
declare const RlMetadataList: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
22
|
+
type RlMetadataList = ReturnType<typeof RlMetadataList>;
|
|
23
|
+
export default RlMetadataList;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<!-- src/lib/components/dataview/RLMetadataTable.svelte -->
|
|
2
2
|
<script lang="ts">
|
|
3
3
|
import type { ColumnMetadata, ColumnReference, EnumMetadata } from '@yrrrrrf/prism-ts';
|
|
4
|
+
import { formatReferenceText } from '../../tools/form-helpers.js';
|
|
4
5
|
|
|
5
6
|
let {
|
|
6
7
|
title,
|
|
@@ -18,10 +19,6 @@
|
|
|
18
19
|
onEnumClick?: (enumData: { name: string; values: string[] }) => void; // Make optional
|
|
19
20
|
}>();
|
|
20
21
|
|
|
21
|
-
function formatReferenceText(ref: ColumnReference | undefined): string {
|
|
22
|
-
if (!ref) return '';
|
|
23
|
-
return `${ref.schema}.${ref.table}.${ref.column}`;
|
|
24
|
-
}
|
|
25
22
|
|
|
26
23
|
function handleFkButtonClick(ref: ColumnReference | undefined) {
|
|
27
24
|
if (ref && onFkClick) {
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<!-- src/lib/components/explorer/RLEnumDisplay.svelte -->
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
import type { RLEnumMetadata } from '../stores/explorer.svelte';
|
|
4
|
+
import RLMetadataList from '../dataview/RLMetadataList.svelte'; // Adjust path as needed
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
enumData,
|
|
8
|
+
// Optional: if RLEnumDisplay should have its own modal button.
|
|
9
|
+
// Otherwise, RLSchemaExplorer can handle showing the modal if needed via context.
|
|
10
|
+
// For simplicity, let's assume any modal action is handled by the parent (RLSchemaExplorer).
|
|
11
|
+
} = $props<{
|
|
12
|
+
enumData: RLEnumMetadata;
|
|
13
|
+
}>();
|
|
14
|
+
|
|
15
|
+
let enumValueItems = $derived(
|
|
16
|
+
enumData.values.map((value: string) => ({
|
|
17
|
+
name: value,
|
|
18
|
+
}))
|
|
19
|
+
);
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<div class="py-2">
|
|
23
|
+
<RLMetadataList items={enumValueItems} title="Values" emptyText="No values defined for this enum." />
|
|
24
|
+
<!--
|
|
25
|
+
If RLSchemaExplorer needs a way to open its existing enum modal from here,
|
|
26
|
+
you could add a button and an on:click event that bubbles up or calls a prop function.
|
|
27
|
+
Example:
|
|
28
|
+
<div class="mt-2">
|
|
29
|
+
<button class="btn btn-xs btn-outline" on:click>
|
|
30
|
+
Show in Modal (if needed)
|
|
31
|
+
</button>
|
|
32
|
+
</div>
|
|
33
|
+
-->
|
|
34
|
+
</div>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { RLEnumMetadata } from '../stores/explorer.svelte';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
enumData: RLEnumMetadata;
|
|
4
|
+
};
|
|
5
|
+
declare const RlEnumDisplay: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
6
|
+
type RlEnumDisplay = ReturnType<typeof RlEnumDisplay>;
|
|
7
|
+
export default RlEnumDisplay;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<!-- src/lib/components/explorer/RLFunctionDisplay.svelte -->
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
import type { RLApiInterfaceActionParams, RLFunctionMetadata, RLFunctionParameter } from '../stores/explorer.svelte';
|
|
4
|
+
|
|
5
|
+
import RLDetailRow from '../dataview/RLDetailRow.svelte';
|
|
6
|
+
import RLMetadataList from '../dataview/RLMetadataList.svelte';
|
|
7
|
+
import type { RLMetadataListItem } from '../dataview/RLMetadataList.svelte';
|
|
8
|
+
import RLApiInterface from '../api/RLApiInterface.svelte'; // For execution
|
|
9
|
+
|
|
10
|
+
let {
|
|
11
|
+
func,
|
|
12
|
+
onOpenApiModal, // Callback to RLSchemaExplorer
|
|
13
|
+
} = $props<{
|
|
14
|
+
func: RLFunctionMetadata;
|
|
15
|
+
onOpenApiModal: (params: RLApiInterfaceActionParams & { schemaName: string, resourceName: string, resourceType: 'function', options: any }) => void;
|
|
16
|
+
}>();
|
|
17
|
+
|
|
18
|
+
let parameterItems = $derived(
|
|
19
|
+
func.parameters.map((param: RLFunctionParameter): RLMetadataListItem => ({
|
|
20
|
+
name: param.name,
|
|
21
|
+
typeInfo: param.type + (param.defaultValue ? ` (default: ${param.defaultValue})` : ''),
|
|
22
|
+
required: !param.hasDefault && param.mode === 'IN', // Only IN params can be "required" in a form sense
|
|
23
|
+
details: [{ text: param.mode, class: `badge-${param.mode === 'IN' ? 'info' : param.mode === 'OUT' ? 'success' : 'warning'}` }],
|
|
24
|
+
}))
|
|
25
|
+
);
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<div class="space-y-3 py-2">
|
|
29
|
+
{#if func.description}
|
|
30
|
+
<RLDetailRow name="Description" typeInfo={func.description} nameClass="font-semibold opacity-80" typeInfoClass="italic text-sm" />
|
|
31
|
+
{/if}
|
|
32
|
+
|
|
33
|
+
<RLDetailRow name="Kind" typeInfo={func.kind} nameClass="font-semibold opacity-80" />
|
|
34
|
+
<RLDetailRow name="Return Type" typeInfo={func.returnType || 'void'} nameClass="font-semibold opacity-80" />
|
|
35
|
+
<RLDetailRow name="Is Strict" typeInfo={func.isStrict ? 'Yes' : 'No'} nameClass="font-semibold opacity-80" />
|
|
36
|
+
|
|
37
|
+
{#if func.kind === 'TRIGGER' && func.triggerData}
|
|
38
|
+
<RLMetadataList title="Trigger Details" items={[
|
|
39
|
+
{ name: 'Timing', typeInfo: func.triggerData.timing },
|
|
40
|
+
{ name: 'Events', typeInfo: func.triggerData.events.join(', ') },
|
|
41
|
+
{ name: 'Target', typeInfo: `${func.triggerData.targetTableSchema}.${func.triggerData.targetTableName}` },
|
|
42
|
+
]} />
|
|
43
|
+
{/if}
|
|
44
|
+
|
|
45
|
+
<RLMetadataList items={parameterItems} title="Parameters" emptyText="No parameters." />
|
|
46
|
+
|
|
47
|
+
{#if (func.kind === 'FUNCTION' || func.kind === 'PROCEDURE') && onOpenApiModal}
|
|
48
|
+
<div class="mt-4 pt-3 border-t border-base-300/30">
|
|
49
|
+
<RLApiInterface
|
|
50
|
+
schemaName={func.schema}
|
|
51
|
+
resourceName={func.name}
|
|
52
|
+
resourceType={'function'}
|
|
53
|
+
columns={[]}
|
|
54
|
+
onOpenModal={(opParams) => onOpenApiModal({
|
|
55
|
+
...opParams,
|
|
56
|
+
schemaName: func.schema,
|
|
57
|
+
resourceName: func.name,
|
|
58
|
+
resourceType: 'function',
|
|
59
|
+
options: { functionParams: func.parameters } // Passing RLFunctionParameter[]
|
|
60
|
+
})}
|
|
61
|
+
/>
|
|
62
|
+
</div>
|
|
63
|
+
{/if}
|
|
64
|
+
</div>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { RLApiInterfaceActionParams, RLFunctionMetadata } from '../stores/explorer.svelte';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
func: RLFunctionMetadata;
|
|
4
|
+
onOpenApiModal: (params: RLApiInterfaceActionParams & {
|
|
5
|
+
schemaName: string;
|
|
6
|
+
resourceName: string;
|
|
7
|
+
resourceType: 'function';
|
|
8
|
+
options: any;
|
|
9
|
+
}) => void;
|
|
10
|
+
};
|
|
11
|
+
declare const RlFunctionDisplay: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
12
|
+
type RlFunctionDisplay = ReturnType<typeof RlFunctionDisplay>;
|
|
13
|
+
export default RlFunctionDisplay;
|