appflare 0.2.40 → 0.2.41
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.
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { DiscoveredHandlerOperation } from "../../../../utils/handler-discovery";
|
|
2
|
+
|
|
3
|
+
export type TreeNode = {
|
|
4
|
+
name: string;
|
|
5
|
+
type: "folder";
|
|
6
|
+
children: TreeNode[];
|
|
7
|
+
handlers: DiscoveredHandlerOperation[];
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export function buildFunctionTree(
|
|
11
|
+
handlers: DiscoveredHandlerOperation[],
|
|
12
|
+
): TreeNode[] {
|
|
13
|
+
const root: TreeNode = {
|
|
14
|
+
name: "root",
|
|
15
|
+
type: "folder",
|
|
16
|
+
children: [],
|
|
17
|
+
handlers: [],
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
for (const handler of handlers) {
|
|
21
|
+
const segments = handler.clientSegments ?? [handler.exportName];
|
|
22
|
+
let current = root;
|
|
23
|
+
|
|
24
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
25
|
+
const segment = segments[i];
|
|
26
|
+
let child = current.children.find(
|
|
27
|
+
(c) => c.name === segment && c.type === "folder",
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
if (!child) {
|
|
31
|
+
child = {
|
|
32
|
+
name: segment,
|
|
33
|
+
type: "folder",
|
|
34
|
+
children: [],
|
|
35
|
+
handlers: [],
|
|
36
|
+
};
|
|
37
|
+
current.children.push(child);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
current = child;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
current.handlers.push(handler);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return root.children;
|
|
47
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { DiscoveredSchema } from "../../../utils/schema-discovery";
|
|
2
2
|
import { DiscoveredHandlerOperation } from "../../../utils/handler-discovery";
|
|
3
3
|
import { TableInfo } from "../types";
|
|
4
|
+
import { buildFunctionTree, TreeNode } from "./functions/tree-builder";
|
|
4
5
|
|
|
5
6
|
export function collectTablesInfo(schema: DiscoveredSchema): TableInfo[] {
|
|
6
7
|
return schema.tables.map((table) => ({
|
|
@@ -33,35 +34,67 @@ export function buildSidebarTableList(tablesInfo: TableInfo[]): string {
|
|
|
33
34
|
\t\t\t\t\t${tableItems}`;
|
|
34
35
|
}
|
|
35
36
|
|
|
37
|
+
function renderTreeNode(node: TreeNode, depth: number): string {
|
|
38
|
+
const indent = " ".repeat(depth);
|
|
39
|
+
const hasChildren = node.children.length > 0;
|
|
40
|
+
const hasHandlers = node.handlers.length > 0;
|
|
41
|
+
const isExpandable = hasChildren || hasHandlers;
|
|
42
|
+
|
|
43
|
+
let html = "";
|
|
44
|
+
|
|
45
|
+
if (isExpandable) {
|
|
46
|
+
const folderId = `folder-${node.name.replace(/[^a-zA-Z0-9]/g, "-")}-${depth}`;
|
|
47
|
+
html += `\n${indent}<li data-name="${node.name}" class="folder-item">`;
|
|
48
|
+
html += `\n${indent} <details class="group/folder" open>`;
|
|
49
|
+
html += `\n${indent} <summary class="sidebar-link flex items-center gap-2 px-3 py-2 text-sm rounded-lg w-full cursor-pointer list-none">`;
|
|
50
|
+
html += `\n${indent} <iconify-icon icon="solar:folder-bold-duotone" width="16" height="16" class="opacity-50 shrink-0 transition-transform group-open/folder:rotate-0"></iconify-icon>`;
|
|
51
|
+
html += `\n${indent} <span class="truncate font-medium">${node.name}</span>`;
|
|
52
|
+
html += `\n${indent} </summary>`;
|
|
53
|
+
html += `\n${indent} <ul class="flex flex-col gap-0.5 ml-4 border-l border-base-200 pl-2">`;
|
|
54
|
+
|
|
55
|
+
for (const child of node.children) {
|
|
56
|
+
html += renderTreeNode(child, depth + 2);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
for (const handler of node.handlers) {
|
|
60
|
+
const icon = handler.kind === "query" ? "solar:reorder-linear" : "solar:bolt-linear";
|
|
61
|
+
html += `\n${indent} <li data-name="${handler.exportName}">`;
|
|
62
|
+
html += `\n${indent} <a href="/admin/functions${handler.routePath}" hx-get="/admin/functions${handler.routePath}" hx-target="#main-content" hx-push-url="true" hx-swap="outerHTML" class="sidebar-link flex items-center gap-2 px-3 py-2 text-sm rounded-lg w-full">`;
|
|
63
|
+
html += `\n${indent} <iconify-icon icon="${icon}" width="16" height="16" class="opacity-50 shrink-0"></iconify-icon>`;
|
|
64
|
+
html += `\n${indent} <span class="truncate">${handler.exportName}</span>`;
|
|
65
|
+
html += `\n${indent} </a>`;
|
|
66
|
+
html += `\n${indent} </li>`;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
html += `\n${indent} </ul>`;
|
|
70
|
+
html += `\n${indent} </details>`;
|
|
71
|
+
html += `\n${indent}</li>`;
|
|
72
|
+
} else {
|
|
73
|
+
for (const handler of node.handlers) {
|
|
74
|
+
const icon = handler.kind === "query" ? "solar:reorder-linear" : "solar:bolt-linear";
|
|
75
|
+
html += `\n${indent}<li data-name="${handler.exportName}">`;
|
|
76
|
+
html += `\n${indent} <a href="/admin/functions${handler.routePath}" hx-get="/admin/functions${handler.routePath}" hx-target="#main-content" hx-push-url="true" hx-swap="outerHTML" class="sidebar-link flex items-center gap-2 px-3 py-2 text-sm rounded-lg w-full">`;
|
|
77
|
+
html += `\n${indent} <iconify-icon icon="${icon}" width="16" height="16" class="opacity-50 shrink-0"></iconify-icon>`;
|
|
78
|
+
html += `\n${indent} <span class="truncate">${handler.exportName}</span>`;
|
|
79
|
+
html += `\n${indent} </a>`;
|
|
80
|
+
html += `\n${indent}</li>`;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return html;
|
|
85
|
+
}
|
|
86
|
+
|
|
36
87
|
export function buildSidebarFunctionList(
|
|
37
88
|
handlers: DiscoveredHandlerOperation[],
|
|
38
89
|
): string {
|
|
39
90
|
const queries = handlers.filter((h) => h.kind === "query");
|
|
40
91
|
const mutations = handlers.filter((h) => h.kind === "mutation");
|
|
41
92
|
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
(h) => `
|
|
45
|
-
<li data-name="${h.exportName}">
|
|
46
|
-
<a href="/admin/functions${h.routePath}" hx-get="/admin/functions${h.routePath}" hx-target="#main-content" hx-push-url="true" hx-swap="outerHTML" class="sidebar-link flex items-center gap-2 px-3 py-2 text-sm rounded-lg w-full">
|
|
47
|
-
<iconify-icon icon="solar:reorder-linear" width="16" height="16" class="opacity-50 shrink-0"></iconify-icon>
|
|
48
|
-
<span class="truncate">${h.exportName}</span>
|
|
49
|
-
</a>
|
|
50
|
-
</li>`,
|
|
51
|
-
)
|
|
52
|
-
.join("");
|
|
93
|
+
const queryTree = buildFunctionTree(queries);
|
|
94
|
+
const mutationTree = buildFunctionTree(mutations);
|
|
53
95
|
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
(h) => `
|
|
57
|
-
<li data-name="${h.exportName}">
|
|
58
|
-
<a href="/admin/functions${h.routePath}" hx-get="/admin/functions${h.routePath}" hx-target="#main-content" hx-push-url="true" hx-swap="outerHTML" class="sidebar-link flex items-center gap-2 px-3 py-2 text-sm rounded-lg w-full">
|
|
59
|
-
<iconify-icon icon="solar:bolt-linear" width="16" height="16" class="opacity-50 shrink-0"></iconify-icon>
|
|
60
|
-
<span class="truncate">${h.exportName}</span>
|
|
61
|
-
</a>
|
|
62
|
-
</li>`,
|
|
63
|
-
)
|
|
64
|
-
.join("");
|
|
96
|
+
const queryItems = queryTree.map((node) => renderTreeNode(node, 0)).join("");
|
|
97
|
+
const mutationItems = mutationTree.map((node) => renderTreeNode(node, 0)).join("");
|
|
65
98
|
|
|
66
99
|
return `
|
|
67
100
|
<div id="pane-functions" class="flex flex-col h-full hidden">
|
|
@@ -112,6 +112,23 @@ function Layout(props: { children: any; title: string; hideSidebar?: boolean })
|
|
|
112
112
|
}
|
|
113
113
|
.sidebar-link:hover iconify-icon { opacity: 0.7; }
|
|
114
114
|
|
|
115
|
+
.folder-item { list-style: none; }
|
|
116
|
+
.folder-item > details > summary { list-style: none; }
|
|
117
|
+
.folder-item > details > summary::-webkit-details-marker { display: none; }
|
|
118
|
+
.folder-item > details > summary::before {
|
|
119
|
+
content: '';
|
|
120
|
+
display: inline-block;
|
|
121
|
+
width: 16px;
|
|
122
|
+
height: 16px;
|
|
123
|
+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='currentColor'%3E%3Cpath d='M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6z'/%3E%3C/svg%3E");
|
|
124
|
+
background-size: contain;
|
|
125
|
+
transition: transform 0.15s ease;
|
|
126
|
+
opacity: 0.45;
|
|
127
|
+
}
|
|
128
|
+
.folder-item > details[open] > summary::before {
|
|
129
|
+
transform: rotate(90deg);
|
|
130
|
+
}
|
|
131
|
+
|
|
115
132
|
.table th {
|
|
116
133
|
font-weight: 500;
|
|
117
134
|
font-size: 0.78rem;
|
|
@@ -291,9 +308,24 @@ function Layout(props: { children: any; title: string; hideSidebar?: boolean })
|
|
|
291
308
|
|
|
292
309
|
function filterFunctions(query) {
|
|
293
310
|
var q = query.toLowerCase();
|
|
311
|
+
document.querySelectorAll('#pane-functions details').forEach(function(details) {
|
|
312
|
+
details.open = true;
|
|
313
|
+
});
|
|
294
314
|
document.querySelectorAll('#pane-functions li').forEach(function(li) {
|
|
295
315
|
var name = (li.getAttribute('data-name') || li.textContent).toLowerCase();
|
|
296
|
-
|
|
316
|
+
var matches = name.includes(q);
|
|
317
|
+
li.style.display = matches ? '' : 'none';
|
|
318
|
+
if (!matches && li.classList.contains('folder-item')) {
|
|
319
|
+
var childItems = li.querySelectorAll('li');
|
|
320
|
+
childItems.forEach(function(child) {
|
|
321
|
+
var childName = (child.getAttribute('data-name') || child.textContent).toLowerCase();
|
|
322
|
+
if (childName.includes(q)) {
|
|
323
|
+
li.style.display = '';
|
|
324
|
+
var parentDetails = li.closest('details');
|
|
325
|
+
if (parentDetails) parentDetails.open = true;
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
}
|
|
297
329
|
});
|
|
298
330
|
}
|
|
299
331
|
|