Skip to content

Commit

Permalink
Merge pull request #96 from ScottLogic/feature/query-history
Browse files Browse the repository at this point in the history
feat: add query history

Closes #62
  • Loading branch information
OiNutter authored Nov 11, 2021
2 parents 46fd753 + 3512c65 commit ad58069
Show file tree
Hide file tree
Showing 3 changed files with 214 additions and 0 deletions.
21 changes: 21 additions & 0 deletions src/components/EditorWindow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import useResizeObserver from "@react-hook/resize-observer";
import syntax from "../editor/syntax";
import theme from "../editor/theme";
import { editorWindow, editorWrapper } from "../style";
import QueryHistory from "./QueryHistory";

type IStandaloneCodeEditor = monaco.editor.IStandaloneCodeEditor;

Expand Down Expand Up @@ -53,6 +54,8 @@ const EditorWindow: FunctionComponent<EditorWindowProps> = ({
const uiTheme = useTheme();

const [currentScript, setCurrentScript] = useState("");
const [showHistory, setShowHistory] = useState(false);
const [queryHistory, setQueryHistory] = useState<string[]>([]);

// Find out if system is in dark mode so we can use the appropriate editor theme
const [isDarkMode, setIsDarkMode] = useState(false);
Expand Down Expand Up @@ -216,8 +219,12 @@ const EditorWindow: FunctionComponent<EditorWindowProps> = ({
// If selected text use that, otherwise send full script
script = selected && selected != "" ? selected : currentScript;

// Remove trailing ;
if (script) script = script.replace(/;$/, "");

// Story query in query history
setQueryHistory((h) => [...h, script]);

// Load actual results
onExecuteQuery(script);
}
Expand Down Expand Up @@ -273,6 +280,15 @@ const EditorWindow: FunctionComponent<EditorWindowProps> = ({
saveScript();
},
},
{
key: "history",
title: "Query History",
iconProps: { iconName: "FullHistory" },
className: "history-button",
onClick: () => {
setShowHistory(true);
},
},
];

const overflowItems: ICommandBarItemProps[] = [
Expand Down Expand Up @@ -376,6 +392,11 @@ const EditorWindow: FunctionComponent<EditorWindowProps> = ({
onChange={updateScripts}
/>
</div>
<QueryHistory
show={showHistory}
history={queryHistory}
onDismiss={() => setShowHistory(false)}
/>
</Stack>
);
};
Expand Down
109 changes: 109 additions & 0 deletions src/components/QueryHistory.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import {
DetailsList,
IColumn,
IconButton,
Panel,
SelectionMode,
Stack,
Text,
} from "@fluentui/react";
import React, { FC, ReactNode } from "react";

interface QueryHistoryProps {
history: string[];
show: boolean;
onDismiss: () => void;
}

const QueryHistory: FC<QueryHistoryProps> = ({
history = [],
show = false,
onDismiss,
}: QueryHistoryProps) => {
const items = history.map((q) => {
return {
query: q, //.substr(0, 100),
actions: ["copy"],
};
});

const columns = [
{
key: "query",
name: "Query",
fieldName: "query",
minWidth: 100,
maxWidth: 200,
isResizable: false,
},
{
key: "actions",
name: "",
fieldName: "actions",
minWidth: 10,
maxWidth: 100,
isResizable: false,
},
];

const copyQuery = (query: string) => {
navigator.clipboard.writeText(query);
onDismiss();
};

const historyActions = {
copy: (query: string) => (
<IconButton
iconProps={{ iconName: "copy" }}
key="copy"
onClick={() => copyQuery(query)}
/>
),
};

const renderHistoryEntry = (
item?: any,
index?: number,
column?: IColumn
): ReactNode => {
if (!column || !item) return <></>;

return (
<>
{column.key === "query" ? (
<>
<Stack verticalAlign="center" style={{ height: "100%" }}>
<Text block={true} nowrap={true}>
{item.query}
</Text>
</Stack>
</>
) : (
item.actions.map((a: keyof typeof historyActions) => {
return historyActions[a](item.query);
})
)}
</>
);
};

return (
<Panel
headerText="History"
isOpen={show}
onDismiss={onDismiss}
className="history-panel"
// You MUST provide this prop! Otherwise screen readers will just say "button" with no label.
closeButtonAriaLabel="Close"
>
<DetailsList
items={items}
columns={columns}
selectionMode={SelectionMode.none}
onRenderItemColumn={renderHistoryEntry}
/>
</Panel>
);
};

export default QueryHistory;
84 changes: 84 additions & 0 deletions tests/query-history.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
const assert = require("assert");
const cleanupDB = require("./cleanup");

const isMac = process.platform === "darwin";

describe("Query History", function () {
before(async function () {
this.timeout(5000);
this.appWindow = await this.app.firstWindow();
await this.appWindow.waitForLoadState("domcontentloaded");
this.modal = await this.appWindow.$(".server-management-modal");
await this.modal.waitForSelector(".server-list li");
const server = await this.modal.$(":nth-match(.server-list li, 1)");
await server.click();
await this.appWindow.waitForTimeout(50);

const connectButton = await this.modal.$('button:has-text("Connect")');

await connectButton.click();
await this.modal.waitForElementState("hidden");

const editor = await this.appWindow.$(".monaco-editor textarea");
const goButton = await this.appWindow.$(".go-button");

const query = "t:flip `name`iq!(`Dent`Beeblebrox`Prefect;98 42 126)";
await editor.press(`${isMac ? "Meta" : "Control"}+a`);
await editor.type(query);
await goButton.click();

const query2 = "tables[]";
await editor.press(`${isMac ? "Meta" : "Control"}+a`);
await editor.type(query2);
await goButton.click();

const query3 = "t";
await editor.press(`${isMac ? "Meta" : "Control"}+a`);
await editor.type(query3);
await goButton.click();

await this.appWindow.waitForSelector(
":nth-match(.table-list .ms-GroupedList-group, 1)"
);
});

it("should display the Query History", async function () {
const historyButton = await this.appWindow.$(".history-button");
await historyButton.click();

const panel = await this.appWindow.waitForSelector(
".ms-Panel.is-open.history-panel"
);
assert.notStrictEqual(panel, null);

const entries = await panel.$$(".ms-DetailsRow");

assert.strictEqual(entries.length, 3);
});

it("should let me select copy a previous query", async function () {
const panel = await this.appWindow.waitForSelector(
".ms-Panel.is-open.history-panel"
);
const row = await panel.$(":nth-match(.ms-DetailsRow, 2)");

const copyButton = await row.$(".ms-Button--icon");
await copyButton.click();

await this.appWindow.waitForSelector(".ms-Panel.is-open.history-panel", {
state: "hidden",
});

const editor = await this.appWindow.$(".monaco-editor textarea");

await editor.press(`${isMac ? "Meta" : "Control"}+a`);
await editor.press(`${isMac ? "Meta" : "Control"}+v`);

assert.strictEqual(await editor.inputValue(), "tables[]");
});

after(async function () {
await cleanupDB("delete t from `.; delete t2 from `.");
await this.appWindow.reload();
});
});

0 comments on commit ad58069

Please sign in to comment.