mirror of
https://github.com/stackrender/stackrender.git
synced 2026-09-10 03:05:42 +00:00
Improved empty content deisgn , add a key for grouped datatypes in the table controller
This commit is contained in:
+1
-1
@@ -32,7 +32,7 @@
|
||||
"fast-json-patch": "^3.1.1",
|
||||
"framer-motion": "11.15.0",
|
||||
"i18next-browser-languagedetector": "^8.0.5",
|
||||
"lodash": "^4.17.21",
|
||||
"lodash": "^4.17.21",
|
||||
"lucide-react": "^0.501.0",
|
||||
"next-themes": "^0.4.6",
|
||||
"node-sql-parser": "^5.3.9",
|
||||
|
||||
@@ -83,10 +83,10 @@ const Autocomplete: React.FC<AutocompleteProps> = ({ items, label = "name", onSe
|
||||
{
|
||||
items ? Object.keys(items).map((key: string) => (
|
||||
<AutocompleteSection
|
||||
key={key.toUpperCase()}
|
||||
classNames={{
|
||||
heading: headingClasses,
|
||||
}}
|
||||
|
||||
title={key.toUpperCase()}
|
||||
>
|
||||
{
|
||||
|
||||
@@ -17,17 +17,17 @@ const EmptyList: React.FC<EmptyListProps> = ({ title, description }) => {
|
||||
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center gap-2 h-full pt-[86px]">
|
||||
<div className="flex flex-col items-center gap-1 h-full pt-[86px] main-linear-background rounded-lg">
|
||||
{
|
||||
<Image
|
||||
width={82}
|
||||
src={"/public/stackrender.png"}
|
||||
width={64}
|
||||
src={"/stackrender.png"}
|
||||
|
||||
/>
|
||||
}
|
||||
{
|
||||
title &&
|
||||
<h1 className="text-font/90 font-bold text-lg">
|
||||
<h1 className="text-font/90 font-bold text-md mt-2">
|
||||
{title}
|
||||
</h1>
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import LanguagesDropdown from "./languages-dropdown";
|
||||
const Navbar: React.FC = ({ }) => {
|
||||
const { database } = useDatabase();
|
||||
return (
|
||||
<nav className="h-12 fixed z-50 bg-background w-full flex items-center p-4 border-b border-divider ">
|
||||
<nav className="h-12 fixed z-50 bg-background w-full flex items-center p-4 border-b border-divider ">
|
||||
<img
|
||||
src={`/stackrender.png`}
|
||||
width={22}
|
||||
@@ -19,17 +19,19 @@ const Navbar: React.FC = ({ }) => {
|
||||
<div className="flex w-full justify-between items-center gap-2">
|
||||
|
||||
<Menu />
|
||||
<div className=" w-full h-full flex items-center justify-center">
|
||||
<div className=" absolute left-[50%] -translate-x-[50%]">
|
||||
{database && <RenameDatabase database={database} />}
|
||||
</div>
|
||||
<a className="gh-button text-font font-medium bg-background text-xs p-4 px-2 pr-2.5 flex justif-center items-center"
|
||||
target="_blank"
|
||||
href="https://github.com/KarimTamani/stackrender">
|
||||
<span className="gh-button__icon"></span>
|
||||
|
||||
</a>
|
||||
<div className="flex gap-2 items-center">
|
||||
<a className="gh-button text-font font-medium bg-background text-xs p-4 px-2 pr-2.5 flex justif-center items-center"
|
||||
target="_blank"
|
||||
href="https://github.com/KarimTamani/stackrender">
|
||||
<span className="gh-button__icon"></span>
|
||||
|
||||
<LanguagesDropdown/>
|
||||
</a>
|
||||
|
||||
<LanguagesDropdown />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@@ -3,29 +3,35 @@ import React, { useEffect, useState } from "react";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "../tooltip/tooltip";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Button, Divider, Image, Input } from "@heroui/react";
|
||||
import { DatabaseDialect, getDatabaseByDialect } from "@/lib/database";
|
||||
import { DatabaseDialect, getDatabaseByDialect } from "@/lib/database";
|
||||
import { Save } from "lucide-react";
|
||||
import { DatabaseType } from "@/lib/schemas/database-schema";
|
||||
|
||||
interface RenameDatabaseProps {
|
||||
database : DatabaseType
|
||||
database: DatabaseType
|
||||
}
|
||||
|
||||
const RenameDatabase: React.FC<RenameDatabaseProps> = ({ database}) => {
|
||||
|
||||
const RenameDatabase: React.FC<RenameDatabaseProps> = ({ database }) => {
|
||||
|
||||
const { editDatabase } = useDatabaseOperations();
|
||||
const [editMode, setEditMode] = useState<boolean>(false);
|
||||
const [dbName, setDbName] = useState<string>(database.name);
|
||||
const { t } = useTranslation();
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
useEffect(() => {
|
||||
setDbName(database.name);
|
||||
}, [database.name])
|
||||
|
||||
const saveDatabaseName = async () => {
|
||||
if (!dbName || dbName.trim().length == 0)
|
||||
return;
|
||||
|
||||
if (dbName.trim() == database.name) {
|
||||
setEditMode(false)
|
||||
|
||||
return;
|
||||
}
|
||||
setIsLoading(true);
|
||||
|
||||
await editDatabase({
|
||||
@@ -39,20 +45,21 @@ const RenameDatabase: React.FC<RenameDatabaseProps> = ({ database}) => {
|
||||
<div className="group">
|
||||
{
|
||||
!editMode &&
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Tooltip >
|
||||
<TooltipTrigger asChild >
|
||||
<label
|
||||
className=" w-full text-editable truncate h-8 px-3 text-sm font-bold dark:text-white flex gap-4 items-center justify-center text-font hover:underline"
|
||||
className=" w-full max-w-[256px] text-editable group-hover:bg-primary-100/5 truncate h-8 px-3 text-sm font-semibold dark:text-white flex gap-4 items-center justify-center text-font hover:underline rounded-small"
|
||||
onDoubleClick={() => setEditMode(true)}
|
||||
>
|
||||
<Image
|
||||
src={getDatabaseByDialect(database.dialect as DatabaseDialect).small_logo}
|
||||
width={20}
|
||||
className="rounded-none "
|
||||
className="rounded-none shring-0 min-w-[20px]"
|
||||
/>
|
||||
|
||||
{dbName}
|
||||
|
||||
<span className="max-w-[164px] truncate">
|
||||
{dbName}
|
||||
</span>
|
||||
</label>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
@@ -80,8 +87,8 @@ const RenameDatabase: React.FC<RenameDatabaseProps> = ({ database}) => {
|
||||
autoFocus
|
||||
className="h-8 w-full focus-visible:ring-0 shadow-none"
|
||||
classNames={{
|
||||
inputWrapper: "rounded-sm focus-visible:border-0 text-sm dark:bg-content1 bg-background group-data-[hover=true]:border-primary group-data-[focus=true]:border-primary border-primary ",
|
||||
input: "font-semibold text-black dark:text-font"
|
||||
inputWrapper: "rounded-small max-w-[256px] focus-visible:border-0 text-sm dark:bg-content1 bg-background group-data-[hover=true]:border-primary group-data-[hover=true]:bg-primary-100/5 group-data-[focus=true]:border-primary border-primary ",
|
||||
input: "font-medium text-font dark:text-font"
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
|
||||
+7
-3
@@ -137,8 +137,8 @@ const TableAccordionHeader: React.FC<TableAccordionHeaderProps> = ({ table, isOp
|
||||
|
||||
!editMode && <>
|
||||
<div className="hidden shrink-0 flex-row group-hover:flex">
|
||||
|
||||
|
||||
|
||||
|
||||
<Button
|
||||
size="sm"
|
||||
isIconOnly
|
||||
@@ -157,10 +157,13 @@ const TableAccordionHeader: React.FC<TableAccordionHeaderProps> = ({ table, isOp
|
||||
>
|
||||
<Focus className="size-4 " />
|
||||
</Button>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<Popover placement="bottom" radius="sm" shadow="sm" showArrow isOpen={popOverOpen} onOpenChange={setPopOverOpen}>
|
||||
<PopoverTrigger>
|
||||
|
||||
<Button
|
||||
size="sm"
|
||||
isIconOnly
|
||||
@@ -168,7 +171,8 @@ const TableAccordionHeader: React.FC<TableAccordionHeaderProps> = ({ table, isOp
|
||||
className="text-icon hover:bg-default hover:text-font/90"
|
||||
>
|
||||
<EllipsisVertical className="size-4 " />
|
||||
</Button>
|
||||
</Button>
|
||||
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-[160px]" >
|
||||
<div className="w-full flex flex-col gap-2 ">
|
||||
|
||||
@@ -20,7 +20,7 @@ const PADDING_Y = 80;
|
||||
|
||||
const TablesController: React.FC = ({ }) => {
|
||||
|
||||
const { database , isSyncing } = useDatabase();
|
||||
const { database } = useDatabase();
|
||||
const { createTable, getInteger } = useDatabaseOperations();
|
||||
const { getViewport } = useReactFlow();
|
||||
const { tables: allTables } = database || { tables: [] };
|
||||
@@ -31,7 +31,7 @@ const TablesController: React.FC = ({ }) => {
|
||||
const { focusedTableId } = useDiagram();
|
||||
const nameRef: Ref<HTMLInputElement> = useRef<HTMLInputElement>(null);
|
||||
const accordionRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
|
||||
useEffect(() => searchTables(), [allTables]);
|
||||
|
||||
const addNewTable = useCallback(async () => {
|
||||
@@ -157,6 +157,7 @@ const TablesController: React.FC = ({ }) => {
|
||||
<AccordionItem
|
||||
key={table.id}
|
||||
id={table.id}
|
||||
|
||||
aria-label={table.name}
|
||||
classNames={{
|
||||
trigger: "w-full h-12 hover:bg-default transition-all duration-200 dark:hover:bg-background",
|
||||
@@ -168,8 +169,11 @@ const TablesController: React.FC = ({ }) => {
|
||||
isOpen={selectedTableId == table.id}
|
||||
table={table}
|
||||
/>
|
||||
}>
|
||||
}
|
||||
|
||||
>
|
||||
<TableAccordionBody table={table} />
|
||||
|
||||
</AccordionItem>
|
||||
))}
|
||||
</Accordion>
|
||||
@@ -184,7 +188,7 @@ const TablesController: React.FC = ({ }) => {
|
||||
</div>
|
||||
}
|
||||
{
|
||||
!isSyncing && allTables.length == 0 &&
|
||||
allTables.length == 0 &&
|
||||
<EmptyList
|
||||
title={t("db_controller.empty_list.no_tables")}
|
||||
description={t("db_controller.empty_list.no_tables_description")}
|
||||
|
||||
@@ -1,29 +1,25 @@
|
||||
import Modal, { ModalProps } from "@/components/modal/modal";
|
||||
import { getDatabaseByDialect } from "@/lib/database";
|
||||
import { DatabaseType } from "@/lib/schemas/database-schema";
|
||||
|
||||
import { useDatabase, useDatabaseOperations } from "@/providers/database-provider/database-provider";
|
||||
|
||||
import { Image, Pagination, Selection, Table, TableBody, TableCell, TableColumn, TableHeader, TableRow } from "@heroui/react";
|
||||
import { Key, useState } from "react";
|
||||
import { Image, Selection, Table, TableBody, TableCell, TableColumn, TableHeader, TableRow } from "@heroui/react";
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const OpenDatabaseModal: React.FC<ModalProps> = (props) => {
|
||||
const { isOpen, onOpenChange } = props;
|
||||
const { t } = useTranslation();
|
||||
const { databases, currentDatabaseId } = useDatabase();
|
||||
|
||||
|
||||
const { switchDatabase } = useDatabaseOperations();
|
||||
const [selectedDatabase, setSelectedDatabase] = useState<any | undefined>(
|
||||
(() => currentDatabaseId ? new Set([currentDatabaseId]) : undefined)
|
||||
);
|
||||
|
||||
const openDatabase = () => {
|
||||
switchDatabase(selectedDatabase.currentKey);
|
||||
if (selectedDatabase.currentKey)
|
||||
switchDatabase(selectedDatabase.currentKey);
|
||||
onOpenChange && onOpenChange(false);
|
||||
}
|
||||
|
||||
@@ -51,13 +47,13 @@ const OpenDatabaseModal: React.FC<ModalProps> = (props) => {
|
||||
selectionMode="single"
|
||||
selectedKeys={selectedDatabase}
|
||||
onSelectionChange={onSelectionChange}
|
||||
|
||||
|
||||
classNames={{
|
||||
wrapper: "shadow-sm border-1 border-divider dark:bg-background-100 rounded-sm",
|
||||
th: "dark:bg-background font-bold text-center rounded-sm",
|
||||
tr: " hover:bg-default-100 h-10 dark:hover:bg-background rounded-lg cursor-pointer text-font/90 transition-colors duration-200 ",
|
||||
base: "max-h-[520px] overflow-y-scroll ",
|
||||
td: "items-center text-center" ,
|
||||
td: "items-center text-center",
|
||||
}}
|
||||
>
|
||||
<TableHeader className="rounded-sm">
|
||||
|
||||
@@ -6,12 +6,6 @@ import { AppSchema, drizzleSchema } from '@/lib/schemas/app-schema';
|
||||
import { StackRenderConnector } from '@/utils/stackrender-connector';
|
||||
import { CircularProgress } from '@heroui/react';
|
||||
import { PowerSyncSQLiteDatabase, wrapPowerSyncWithDrizzle } from '@powersync/drizzle-driver';
|
||||
import { data_types, DataInsertType } from '@/lib/schemas/data-type-schema';
|
||||
import { MysqlDataType } from '@/lib/data_types/mysql_data_types';
|
||||
import { PostgresDataType } from '@/lib/data_types/postgres_data_types';
|
||||
import { SqliteDataTypes } from '@/lib/data_types/sqlite_data_types';
|
||||
import { MariaDbDataType } from '@/lib/data_types/mariadb_data_types';
|
||||
import { DatabaseDialect } from '@/lib/database';
|
||||
import { seedDataTypes } from '@/lib/data_types/seed_datatypes';
|
||||
|
||||
|
||||
@@ -26,6 +20,7 @@ export const powerSyncDb = new PowerSyncDatabase({
|
||||
export const db: PowerSyncSQLiteDatabase<typeof drizzleSchema> = wrapPowerSyncWithDrizzle(powerSyncDb, {
|
||||
schema: drizzleSchema,
|
||||
});
|
||||
|
||||
const ConnectorContext = createContext<StackRenderConnector | null>(null);
|
||||
export const useConnector = () => useContext(ConnectorContext);
|
||||
|
||||
|
||||
@@ -418,3 +418,9 @@ html {
|
||||
animation-duration: 0.01ms !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.main-linear-background {
|
||||
background: linear-gradient(180deg, rgb(140 104 255 / 15%) -1.95%, rgb(131 92 255 / 0%) 20.34%), #ffffff00;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user