mirror of
https://github.com/zadam/trilium.git
synced 2025-10-20 23:29:02 +02:00
feat(react/widgets): port sql_result
This commit is contained in:
parent
4df94d1f20
commit
735e91e636
@ -11,21 +11,7 @@ import froca from "../services/froca.js";
|
|||||||
import linkService from "../services/link.js";
|
import linkService from "../services/link.js";
|
||||||
import { t } from "../services/i18n.js";
|
import { t } from "../services/i18n.js";
|
||||||
import type FNote from "../entities/fnote.js";
|
import type FNote from "../entities/fnote.js";
|
||||||
|
import { CreateChildrenResponse, SqlExecuteResponse } from "@triliumnext/commons";
|
||||||
// TODO: Move somewhere else nicer.
|
|
||||||
export type SqlExecuteResults = string[][][];
|
|
||||||
|
|
||||||
// TODO: Deduplicate with server.
|
|
||||||
interface SqlExecuteResponse {
|
|
||||||
success: boolean;
|
|
||||||
error?: string;
|
|
||||||
results: SqlExecuteResults;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Deduplicate with server.
|
|
||||||
interface CreateChildrenResponse {
|
|
||||||
note: FNote;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class Entrypoints extends Component {
|
export default class Entrypoints extends Component {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -42,6 +42,7 @@ import FloatingButtons from "../widgets/FloatingButtons.jsx";
|
|||||||
import { DESKTOP_FLOATING_BUTTONS } from "../widgets/FloatingButtonsDefinitions.jsx";
|
import { DESKTOP_FLOATING_BUTTONS } from "../widgets/FloatingButtonsDefinitions.jsx";
|
||||||
import SearchResult from "../widgets/search_result.jsx";
|
import SearchResult from "../widgets/search_result.jsx";
|
||||||
import GlobalMenu from "../widgets/buttons/global_menu.jsx";
|
import GlobalMenu from "../widgets/buttons/global_menu.jsx";
|
||||||
|
import SqlResults from "../widgets/sql_result.js";
|
||||||
|
|
||||||
export default class DesktopLayout {
|
export default class DesktopLayout {
|
||||||
|
|
||||||
@ -140,7 +141,7 @@ export default class DesktopLayout {
|
|||||||
.child(new NoteDetailWidget())
|
.child(new NoteDetailWidget())
|
||||||
.child(new NoteListWidget(false))
|
.child(new NoteListWidget(false))
|
||||||
.child(<SearchResult />)
|
.child(<SearchResult />)
|
||||||
.child(new SqlResultWidget())
|
.child(<SqlResults />)
|
||||||
.child(<ScrollPadding />)
|
.child(<ScrollPadding />)
|
||||||
)
|
)
|
||||||
.child(new ApiLogWidget())
|
.child(new ApiLogWidget())
|
||||||
|
7
apps/client/src/widgets/sql_result.css
Normal file
7
apps/client/src/widgets/sql_result.css
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
.sql-result-widget {
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sql-console-result-container td {
|
||||||
|
white-space: preserve;
|
||||||
|
}
|
@ -1,88 +0,0 @@
|
|||||||
import type { EventData } from "../components/app_context.js";
|
|
||||||
import { t } from "../services/i18n.js";
|
|
||||||
import NoteContextAwareWidget from "./note_context_aware_widget.js";
|
|
||||||
|
|
||||||
const TPL = /*html*/`
|
|
||||||
<div class="sql-result-widget">
|
|
||||||
<style>
|
|
||||||
.sql-result-widget {
|
|
||||||
padding: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sql-console-result-container td {
|
|
||||||
white-space: preserve;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<div class="sql-query-no-rows alert alert-info" style="display: none;">
|
|
||||||
${t("sql_result.no_rows")}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="sql-console-result-container"></div>
|
|
||||||
</div>`;
|
|
||||||
|
|
||||||
export default class SqlResultWidget extends NoteContextAwareWidget {
|
|
||||||
|
|
||||||
private $resultContainer!: JQuery<HTMLElement>;
|
|
||||||
private $noRowsAlert!: JQuery<HTMLElement>;
|
|
||||||
|
|
||||||
isEnabled() {
|
|
||||||
return this.note && this.note.mime === "text/x-sqlite;schema=trilium" && super.isEnabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
doRender() {
|
|
||||||
this.$widget = $(TPL);
|
|
||||||
|
|
||||||
this.$resultContainer = this.$widget.find(".sql-console-result-container");
|
|
||||||
this.$noRowsAlert = this.$widget.find(".sql-query-no-rows");
|
|
||||||
}
|
|
||||||
|
|
||||||
async sqlQueryResultsEvent({ ntxId, results }: EventData<"sqlQueryResults">) {
|
|
||||||
if (!this.isNoteContext(ntxId)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$noRowsAlert.toggle(results.length === 1 && results[0].length === 0);
|
|
||||||
this.$resultContainer.toggle(results.length > 1 || results[0].length > 0);
|
|
||||||
|
|
||||||
this.$resultContainer.empty();
|
|
||||||
|
|
||||||
for (const rows of results) {
|
|
||||||
if (typeof rows === "object" && !Array.isArray(rows)) {
|
|
||||||
// inserts, updates
|
|
||||||
this.$resultContainer
|
|
||||||
.empty()
|
|
||||||
.show()
|
|
||||||
.append($("<pre>").text(JSON.stringify(rows, null, "\t")));
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!rows.length) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const $table = $('<table class="table table-striped">');
|
|
||||||
this.$resultContainer.append($table);
|
|
||||||
|
|
||||||
const result = rows[0];
|
|
||||||
const $row = $("<tr>");
|
|
||||||
|
|
||||||
for (const key in result) {
|
|
||||||
$row.append($("<th>").text(key));
|
|
||||||
}
|
|
||||||
|
|
||||||
$table.append($row);
|
|
||||||
|
|
||||||
for (const result of rows) {
|
|
||||||
const $row = $("<tr>");
|
|
||||||
|
|
||||||
for (const key in result) {
|
|
||||||
$row.append($("<td>").text(result[key]));
|
|
||||||
}
|
|
||||||
|
|
||||||
$table.append($row);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
62
apps/client/src/widgets/sql_result.tsx
Normal file
62
apps/client/src/widgets/sql_result.tsx
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import { SqlExecuteResults } from "@triliumnext/commons";
|
||||||
|
import { useNoteContext, useTriliumEvent } from "./react/hooks";
|
||||||
|
import "./sql_result.css";
|
||||||
|
import { useState } from "preact/hooks";
|
||||||
|
import Alert from "./react/Alert";
|
||||||
|
import { t } from "../services/i18n";
|
||||||
|
|
||||||
|
export default function SqlResults() {
|
||||||
|
const { note, ntxId } = useNoteContext();
|
||||||
|
const [ results, setResults ] = useState<SqlExecuteResults>();
|
||||||
|
|
||||||
|
useTriliumEvent("sqlQueryResults", ({ ntxId: eventNtxId, results }) => {
|
||||||
|
if (eventNtxId !== ntxId) return;
|
||||||
|
setResults(results);
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="sql-result-widget">
|
||||||
|
{note?.mime === "text/x-sqlite;schema=trilium" && (
|
||||||
|
results?.length === 1 && Array.isArray(results[0]) && results[0].length === 0 ? (
|
||||||
|
<Alert type="info">
|
||||||
|
{t("sql_result.no_rows")}
|
||||||
|
</Alert>
|
||||||
|
) : (
|
||||||
|
<div class="sql-console-result-container">
|
||||||
|
{results?.map(rows => {
|
||||||
|
// inserts, updates
|
||||||
|
if (typeof rows === "object" && !Array.isArray(rows)) {
|
||||||
|
return <pre>{JSON.stringify(rows, null, "\t")}</pre>
|
||||||
|
}
|
||||||
|
|
||||||
|
// selects
|
||||||
|
return <SqlResultTable rows={rows} />
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function SqlResultTable({ rows }: { rows: object[] }) {
|
||||||
|
if (!rows.length) return;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<table className="table table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
{Object.keys(rows[0]).map(key => <th>{key}</th>)}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
{rows.map(row => (
|
||||||
|
<tr>
|
||||||
|
{Object.values(row).map(cell => <td>{cell}</td>)}
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
)
|
||||||
|
}
|
@ -12,7 +12,7 @@ import ValidationError from "../../errors/validation_error.js";
|
|||||||
import blobService from "../../services/blob.js";
|
import blobService from "../../services/blob.js";
|
||||||
import type { Request } from "express";
|
import type { Request } from "express";
|
||||||
import type BBranch from "../../becca/entities/bbranch.js";
|
import type BBranch from "../../becca/entities/bbranch.js";
|
||||||
import type { AttributeRow, DeleteNotesPreview, MetadataResponse } from "@triliumnext/commons";
|
import type { AttributeRow, CreateChildrenResponse, DeleteNotesPreview, MetadataResponse } from "@triliumnext/commons";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @swagger
|
* @swagger
|
||||||
@ -123,7 +123,7 @@ function createNote(req: Request) {
|
|||||||
return {
|
return {
|
||||||
note,
|
note,
|
||||||
branch
|
branch
|
||||||
};
|
} satisfies CreateChildrenResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateNoteData(req: Request) {
|
function updateNoteData(req: Request) {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { AttachmentRow, AttributeRow, NoteType } from "./rows.js";
|
import { AttachmentRow, AttributeRow, BranchRow, NoteRow, NoteType } from "./rows.js";
|
||||||
|
|
||||||
type Response = {
|
type Response = {
|
||||||
success: true,
|
success: true,
|
||||||
@ -220,3 +220,17 @@ export type BacklinksResponse = ({
|
|||||||
noteId: string;
|
noteId: string;
|
||||||
excerpts: string[]
|
excerpts: string[]
|
||||||
})[];
|
})[];
|
||||||
|
|
||||||
|
|
||||||
|
export type SqlExecuteResults = (object[] | object)[];
|
||||||
|
|
||||||
|
export interface SqlExecuteResponse {
|
||||||
|
success: boolean;
|
||||||
|
error?: string;
|
||||||
|
results: SqlExecuteResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateChildrenResponse {
|
||||||
|
note: NoteRow;
|
||||||
|
branch: BranchRow;
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user