-
Notifications
You must be signed in to change notification settings - Fork 92
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add board tool component and integrate with board layout
- Loading branch information
1 parent
e869720
commit 2e61a66
Showing
7 changed files
with
568 additions
and
61 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,59 @@ | ||
"use client"; | ||
import Board from "@/components/board"; | ||
import { BoardFilter } from "@/components/board/board-filter"; | ||
import { BoardFilterProps } from "@/components/board/board-filter-dialog"; | ||
import { BoardTool } from "@/components/board/board-tool"; | ||
import { useState } from "react"; | ||
import ReactGridLayout from "react-grid-layout"; | ||
|
||
interface DashboardProps { | ||
layout: ReactGridLayout.Layout[]; | ||
data: { | ||
filters: BoardFilterProps[]; | ||
}; | ||
} | ||
|
||
export default function StorybookBoardPage() { | ||
const [layout, setLayout] = useState<ReactGridLayout.Layout[]>([ | ||
{ x: 0, y: 0, w: 1, h: 1, i: "0" }, | ||
{ x: 1, y: 0, w: 1, h: 1, i: "1" }, | ||
{ x: 2, y: 0, w: 1, h: 1, i: "2" }, | ||
{ x: 3, y: 0, w: 1, h: 1, i: "3" }, | ||
]); | ||
const [editMode, setEditMode] = useState< | ||
"ADD_CHART" | "REARRANGING_CHART" | null | ||
>(null); | ||
const [value, setValue] = useState<DashboardProps>({ | ||
layout: [ | ||
{ x: 0, y: 0, w: 1, h: 1, i: "0" }, | ||
{ x: 1, y: 0, w: 1, h: 1, i: "1" }, | ||
{ x: 2, y: 0, w: 1, h: 1, i: "2" }, | ||
{ x: 3, y: 0, w: 1, h: 1, i: "3" }, | ||
], | ||
data: { filters: [] }, | ||
}); | ||
|
||
console.log(value); | ||
|
||
return ( | ||
<div className="bg-secondary min-h-full w-full flex-1"> | ||
<Board layout={layout} onChange={setLayout} /> | ||
<div className="min-h-full w-full flex-1"> | ||
<BoardFilter | ||
filters={value.data.filters} | ||
onFilters={(v) => | ||
setValue({ | ||
...value, | ||
data: { | ||
...value.data, | ||
filters: v, | ||
}, | ||
}) | ||
} | ||
/> | ||
<BoardTool editMode={editMode} setEditMode={setEditMode} /> | ||
<Board | ||
layout={value.layout} | ||
onChange={(v) => | ||
setValue({ | ||
...value, | ||
layout: v, | ||
}) | ||
} | ||
editMode={editMode} | ||
/> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
import { useCallback } from "react"; | ||
import { Button } from "../ui/button"; | ||
import { | ||
Dialog, | ||
DialogContent, | ||
DialogFooter, | ||
DialogHeader, | ||
DialogTitle, | ||
} from "../ui/dialog"; | ||
import { Input } from "../ui/input"; | ||
import { | ||
Select, | ||
SelectContent, | ||
SelectItem, | ||
SelectTrigger, | ||
SelectValue, | ||
} from "../ui/select"; | ||
|
||
export interface BoardFilterProps { | ||
type: string; | ||
name: string; | ||
default_value: string; | ||
value: string; | ||
new?: boolean; | ||
} | ||
|
||
interface Props { | ||
onClose?: () => void; | ||
filter: BoardFilterProps; | ||
onFilter: (v: BoardFilterProps) => void; | ||
onAddFilter?: (v: BoardFilterProps) => void; | ||
} | ||
|
||
const DEFAULT_EMPTY = { | ||
type: "search", | ||
name: "", | ||
default_value: "", | ||
value: "", | ||
}; | ||
|
||
export const DEFAULT_DATE_FILTER = [ | ||
"Not timeframe override", | ||
"Custom date range", | ||
"Last 24 hours", | ||
"Today", | ||
"Yesterday", | ||
"This week", | ||
"This month", | ||
"Last 7 days", | ||
"Last 30 days", | ||
"Last 90 days", | ||
]; | ||
|
||
export function BoardFilterDialog(props: Props) { | ||
let default_value = [...DEFAULT_DATE_FILTER]; | ||
|
||
if (props.filter.type === "enum" && !!props.filter.value) { | ||
default_value = [...props.filter.value.split(",")]; | ||
} | ||
|
||
let allowAddFilter = !!props.filter.name; | ||
|
||
if (props.filter.type === "enum") { | ||
allowAddFilter = !!props.filter.name && !!props.filter.value; | ||
} | ||
|
||
const onAddFilter = useCallback(() => { | ||
props.onAddFilter && props.onAddFilter(props.filter); | ||
}, [props]); | ||
|
||
return ( | ||
<Dialog open onOpenChange={props.onClose}> | ||
<DialogContent> | ||
<DialogHeader> | ||
<DialogTitle>New Filter</DialogTitle> | ||
</DialogHeader> | ||
<div className="flex flex-col gap-2"> | ||
<div className="mb-2"> | ||
<div className="mb-1 text-xs font-medium">Select filter type</div> | ||
<Select | ||
value={props.filter.type} | ||
onValueChange={(v) => | ||
props.onFilter({ ...DEFAULT_EMPTY, type: v }) | ||
} | ||
> | ||
<SelectTrigger> | ||
<SelectValue /> | ||
</SelectTrigger> | ||
<SelectContent> | ||
<SelectItem value="search">Search</SelectItem> | ||
<SelectItem value="enum">Multi-select ENUM</SelectItem> | ||
<SelectItem value="date">Date Rang</SelectItem> | ||
</SelectContent> | ||
</Select> | ||
</div> | ||
<div className="mb-2"> | ||
<div className="mb-1 text-xs font-medium">Filter name*</div> | ||
<Input | ||
placeholder="Enter filter name" | ||
value={props.filter.name} | ||
onChange={(v) => | ||
props.onFilter({ ...props.filter, name: v.target.value }) | ||
} | ||
/> | ||
</div> | ||
{props.filter.type === "enum" && ( | ||
<div className="mb-2"> | ||
<div className="mb-1 text-xs font-medium"> | ||
Values* | ||
<div> | ||
<small className="text-muted-foreground"> | ||
Enter values separated by comma | ||
</small> | ||
</div> | ||
</div> | ||
<Input | ||
placeholder="value 1, value 2, value 3" | ||
value={props.filter.value} | ||
onChange={(v) => | ||
props.onFilter({ ...props.filter, value: v.target.value }) | ||
} | ||
/> | ||
</div> | ||
)} | ||
<div className="mb-2"> | ||
<div className="mb-1 text-xs font-medium"> | ||
Default value (optional) | ||
<div> | ||
<small className="text-muted-foreground"> | ||
If this field is left empty, no filter will be applied by | ||
default | ||
</small> | ||
</div> | ||
</div> | ||
{props.filter.type === "search" ? ( | ||
<Input | ||
placeholder="Enter default value" | ||
value={props.filter.default_value} | ||
onChange={(v) => | ||
props.onFilter({ | ||
...props.filter, | ||
default_value: v.target.value, | ||
}) | ||
} | ||
/> | ||
) : ( | ||
<Select | ||
disabled={default_value.length === 0} | ||
value={props.filter.default_value} | ||
onValueChange={(v) => | ||
props.onFilter({ ...props.filter, default_value: v }) | ||
} | ||
> | ||
<SelectTrigger> | ||
<SelectValue /> | ||
</SelectTrigger> | ||
<SelectContent> | ||
{default_value | ||
.filter((x) => !!x) | ||
.map((x) => { | ||
return ( | ||
<SelectItem key={x} value={x}> | ||
{x} | ||
</SelectItem> | ||
); | ||
})} | ||
</SelectContent> | ||
</Select> | ||
)} | ||
</div> | ||
{props.filter.type !== "date" && !!props.filter.name && ( | ||
<div> | ||
{`Use the variable {{ ${props.filter.name} }} in your charts SQL queries.`} | ||
</div> | ||
)} | ||
</div> | ||
<DialogFooter> | ||
<Button | ||
type="button" | ||
disabled={!allowAddFilter} | ||
onClick={onAddFilter} | ||
> | ||
Add Filter | ||
</Button> | ||
<Button type="button" variant={"secondary"} onClick={props.onClose}> | ||
Cancel | ||
</Button> | ||
</DialogFooter> | ||
</DialogContent> | ||
</Dialog> | ||
); | ||
} |
Oops, something went wrong.