Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature(front): queries history in playground #55

Merged
merged 8 commits into from
Nov 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions crates/web/frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/web/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"copy-webpack-plugin": "^12.0.2",
"framer-motion": "^11.9.0",
"gq-web": "file:pkg",
"idb": "^8.0.0",
"lucide-react": "^0.447.0",
"next": "14.2.14",
"next-themes": "^0.3.0",
Expand Down
24 changes: 12 additions & 12 deletions crates/web/frontend/src/app/global-error.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { cn } from "@/lib/utils";
import { Fira_Mono, Montserrat } from "next/font/google";
import { useEffect } from "react";
import "./globals.css";
import { deleteDatabase } from "@/services/queries/query-service";

const montserrat = Montserrat({ subsets: ["latin"], variable: "--font-sans" });
const firaCode = Fira_Mono({
Expand All @@ -21,6 +22,12 @@ export default function GlobalError({
}) {
useEffect(() => console.error(error), [error]);

const handleTryAgain = async () => {
localStorage.clear();
await deleteDatabase();
window.location.reload();
};

return (
<html lang="en" className="dark">
<body
Expand All @@ -32,21 +39,14 @@ export default function GlobalError({
>
<div
style={{ boxShadow: "0 60px 60px -90px var(--shadow-accent)" }}
className="flex flex-col items-center px-48 py-24 border border-accent-background rounded-lg bg-background"
className="w-[50rem] flex flex-col items-center px-12 py-12 border bg-background"
>
<h2 className="text-4xl font-bold">Something went wrong!</h2>
<p className="text-sm font-light mt-4">
Click the button below to refresh the playground state
<p className="text-sm font-light mt-4 text-center">
Click the button below to refresh the playground state. This will delete all your saved
queries and your settings aiming to solve the issue.
</p>
<Button
className="mt-8"
variant="outline"
type="button"
onClick={() => {
localStorage.clear();
window.location.reload();
}}
>
<Button className="mt-8" variant="outline" type="button" onClick={handleTryAgain}>
Try again
</Button>
</div>
Expand Down
12 changes: 12 additions & 0 deletions crates/web/frontend/src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,15 @@ code {
li[aria-selected="true"] {
@apply !bg-accent-background !text-[var(--code-secondary)];
}

h3 {
@apply text-lg font-semibold leading-none tracking-tight;
}

h4 {
@apply text-base font-semibold leading-none tracking-tight;
}

p {
@apply text-xs;
}
5 changes: 2 additions & 3 deletions crates/web/frontend/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ export default function RootLayout({
<html lang="en">
<body className={cn("min-h-screen antialiased", montserrat.variable, firaCode.variable)}>
<Toaster
offset="32px"
duration={2000}
visibleToasts={4}
expand={false}
Expand All @@ -38,10 +37,10 @@ export default function RootLayout({
unstyled: true,
classNames: {
toast:
"w-full flex gap-4 bg-background items-center border border-accent-background p-4 rounded-md shadow-md",
"w-full flex gap-4 bg-background items-center border border-accent-background p-4 shadow-md",
title: "text-foreground text-sm",
actionButton:
"min-w-max bg-foreground text-background text-xs px-2 py-1 rounded-md justify-self-end",
"min-w-max bg-foreground text-background text-xs px-2 py-1 justify-self-end",
closeButton:
"text-foreground hover:text-accent bg-background transition-colors h-4 w-4",
icon: "",
Expand Down
185 changes: 94 additions & 91 deletions crates/web/frontend/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,21 @@
"use client";

import ActionButton from "@/components/action-button/action-button";
import ApplyButton from "@/components/apply-button/apply-button";
import Editor from "@/components/editor/editor";
import Footer from "@/components/footer/footer";
import Header from "@/components/header/header";
import useDebounce from "@/hooks/useDebounce";
import { LeftSidebar } from "@/components/left-sidebar/left-sidebar";
import useDebounce from "@/hooks/use-debounce";
import { notify } from "@/lib/notify";
import { cn, i } from "@/lib/utils";
import { i } from "@/lib/utils";
import { Data } from "@/model/data";
import FileType from "@/model/file-type";
import { type LoadingState, loading, notLoading } from "@/model/loading-state";
import { setLinkEditors } from "@/model/settings";
import { useSettings } from "@/providers/settings-provider";
import { useWorker } from "@/providers/worker-provider";
import type { CompletionSource } from "@codemirror/autocomplete";
import { Link2, Link2Off } from "lucide-react";
import { useSearchParams } from "next/navigation";
import { type MutableRefObject, Suspense, useCallback, useEffect, useRef, useState } from "react";
import type PromiseWorker from "webworker-promise";
import { applyGq, getQueryCompletionSource, importShare } from "./page-utils";
import styles from "./page.module.css";

const ShareLoader = ({
updateInputEditorCallback,
Expand Down Expand Up @@ -80,6 +75,8 @@ const Home = () => {
const [queryCompletionSource, setQueryCompletionSource] = useState<CompletionSource>();
const [isApplying, setIsApplying] = useState(false);
const [shareLink, setShareLink] = useState<string>();
const [sidebarOpen, setSidebarOpen] = useState(false);
const addNewQueryCallback = useRef<(queryContent: string) => void>(i);
const {
settings: {
autoApplySettings: { autoApply, debounceTime },
Expand All @@ -88,7 +85,7 @@ const Home = () => {
},
setSettings,
} = useSettings();
const debounce = useDebounce(debounceTime);
const debounce = useDebounce();
const { gqWorker, lspWorker } = useWorker();

const updateOutputData = useCallback(
Expand All @@ -114,6 +111,7 @@ const Home = () => {
gqWorker,
silent,
);
addNewQueryCallback.current(queryContent);
setErrorMessage(undefined);
updateOutputEditorCallback.current(result);
} catch (err) {
Expand All @@ -137,6 +135,10 @@ const Home = () => {
[updateOutputData],
);

const handleClickQuery = useCallback((queryContent: string) => {
updateQueryEditorCallback.current(new Data(queryContent, FileType.GQ));
}, []);

const handleChangeInputDataFileType = useCallback(
(fileType: FileType) => {
setShareLink(undefined);
Expand All @@ -153,9 +155,9 @@ const Home = () => {
[linkEditors],
);

const handleChangeLinked = useCallback(() => {
const handleToggleLinked = useCallback(() => {
setSettings((prev) => setLinkEditors(prev, !linkEditors));
notify.info(`${linkEditors ? "Unlinked" : "Linked"} editors!`);
notify.info(`Editors ${linkEditors ? "unlinked" : "linked"}!`);
if (!linkEditors) convertOutputEditorCallback.current(inputType.current);
}, [linkEditors, setSettings]);

Expand All @@ -166,7 +168,7 @@ const Home = () => {
getQueryCompletionSource(lspWorker, new Data(content, inputType.current)),
);
autoApply &&
debounce(() =>
debounce(debounceTime, () =>
updateOutputData(content, inputType.current, queryContent.current, debounceTime < 500),
);
},
Expand All @@ -177,101 +179,102 @@ const Home = () => {
(content: string) => {
setShareLink(undefined);
autoApply &&
debounce(() =>
debounce(debounceTime, () =>
updateOutputData(inputContent.current, inputType.current, content, debounceTime < 500),
);
},
[autoApply, debounce, updateOutputData, debounceTime],
);

return (
<main className="flex flex-col items-center pt-4 px-12 h-screen">
<Header
className="w-full mb-8"
<div className="flex h-screen w-screen overflow-hidden">
<LeftSidebar
open={sidebarOpen}
setOpen={setSidebarOpen}
onClickExample={handleClickExample}
onClickQuery={handleClickQuery}
addNewQueryCallback={addNewQueryCallback}
inputContent={inputContent}
inputType={inputType}
queryContent={queryContent}
outputType={outputType}
shareLink={shareLink}
setShareLink={setShareLink}
/>
<section className="flex items-center justify-center w-full">
<aside className="flex flex-col gap-8">
<Editor
className="w-[44vw] h-[40vh]"
onChangeFileType={handleChangeInputDataFileType}
onChangeContent={handleChangeInputContent}
title="Input"
defaultFileName="input"
fileTypes={[FileType.JSON, FileType.YAML]}
convertCodeCallback={convertInputEditorCallback}
updateCallback={updateInputEditorCallback}
contentRef={inputContent}
typeRef={inputType}
/>
<Editor
className="w-[44vw] h-[40vh]"
onChangeContent={handleChangeQueryContent}
title="Input"
defaultFileName="query"
fileTypes={[FileType.GQ]}
completionSource={queryCompletionSource}
updateCallback={updateQueryEditorCallback}
contentRef={queryContent}
/>
</aside>
<div className="h-full flex justify-center items-center px-8 relative">
<div className="absolute top-40 flex w-full items-center">
<div className={styles.linkLeftBorder} data-linked={linkEditors} />
<ActionButton
className={cn(
"p-2 min-w-max border-2",
linkEditors ? "border-accent" : "border-accent-background",
)}
description={`${linkEditors ? "Link" : "Unlink"} input and output editor file types`}
onClick={handleChangeLinked}
>
{linkEditors ? <Link2 className="w-3 h-3" /> : <Link2Off className="w-3 h-3" />}
</ActionButton>
<div className={styles.linkRightBorder} data-linked={linkEditors} />
</div>
<ApplyButton
autoApply={autoApply}
onClick={() =>
updateOutputData(inputContent.current, inputType.current, queryContent.current, false)
}
/>
</div>
<aside className="flex flex-col">
<Editor
className="w-[44vw] h-[83vh]"
onChangeFileType={handleChangeOutputDataFileType}
title="Output"
editable={false}
defaultFileName="output"
fileTypes={[FileType.JSON, FileType.YAML]}
errorMessage={errorMessage}
onDismissError={() => setErrorMessage(undefined)}
warningMessages={warningMessages}
convertCodeCallback={convertOutputEditorCallback}
loadingCallback={outputEditorLoadingCallback}
updateCallback={updateOutputEditorCallback}
typeRef={outputType}
/>
</aside>
</section>
<Footer className="my-auto" />
<Suspense>
<ShareLoader
updateInputEditorCallback={updateInputEditorCallback}
updateQueryEditorCallback={updateQueryEditorCallback}
updateOutputData={updateOutputData}
gqWorker={gqWorker}
setLinkEditors={(value) => setSettings((prev) => setLinkEditors(prev, value))}
<main className="flex flex-col items-center">
<section className="flex items-center justify-between w-full h-full relative">
<aside className="flex flex-col">
<Editor
width={`calc(50vw - 32px ${sidebarOpen ? "- 192px" : ""})`}
height="calc(50vh - 20px)"
className="border-b transition-all"
onChangeFileType={handleChangeInputDataFileType}
onChangeContent={handleChangeInputContent}
title="Input"
defaultFileName="input"
fileTypes={[FileType.JSON, FileType.YAML]}
convertCodeCallback={convertInputEditorCallback}
updateCallback={updateInputEditorCallback}
contentRef={inputContent}
typeRef={inputType}
/>
<Editor
width={`calc(50vw - 32px ${sidebarOpen ? "- 192px" : ""})`}
height="calc(50vh - 20px)"
className="transition-all"
onChangeContent={handleChangeQueryContent}
onApply={() =>
updateOutputData(
inputContent.current,
inputType.current,
queryContent.current,
false,
)
}
title="Input"
defaultFileName="query"
fileTypes={[FileType.GQ]}
completionSource={queryCompletionSource}
updateCallback={updateQueryEditorCallback}
contentRef={queryContent}
/>
</aside>
<aside className="flex flex-col">
<Editor
width={`calc(50vw - 32px ${sidebarOpen ? "- 192px" : ""})`}
height="calc(100vh - 40px)"
className="border-l transition-all"
onChangeFileType={handleChangeOutputDataFileType}
title="Output"
editable={false}
defaultFileName="output"
fileTypes={[FileType.JSON, FileType.YAML]}
errorMessage={errorMessage}
onDismissError={() => setErrorMessage(undefined)}
warningMessages={warningMessages}
convertCodeCallback={convertOutputEditorCallback}
loadingCallback={outputEditorLoadingCallback}
updateCallback={updateOutputEditorCallback}
typeRef={outputType}
/>
</aside>
</section>
<Footer
className="h-10"
linkEditors={linkEditors}
handleToggleLinked={handleToggleLinked}
/>
</Suspense>
</main>
<Suspense>
<ShareLoader
updateInputEditorCallback={updateInputEditorCallback}
updateQueryEditorCallback={updateQueryEditorCallback}
updateOutputData={updateOutputData}
gqWorker={gqWorker}
setLinkEditors={(value) => setSettings((prev) => setLinkEditors(prev, value))}
/>
</Suspense>
</main>
</div>
);
};

Expand Down
Loading