feat(tagsSelectorComponent): add TagsSelector component to allow users to select tags for a flow
feat(tagsSelectorComponent): add TagComponent to render individual tags in the TagsSelector component fix(API): add tags and publicFlow parameters to saveFlowStore function to save tags and set flow visibility fix(ConfirmationModal): add size prop to allow customizing the size of the modal feat(ExtraSidebar): add TagsSelector component to the Share Flow confirmation modal to allow users to select tags for the flow feat(ExtraSidebar): add ToggleShadComponent to allow users to toggle the visibility of the shared flow fix(ExtraSidebar): pass selected tags and sharePublic value to saveFlowStore function when sharing a flow fix(ExtraSidebar): add useEffect to fetch tags from API and initialize tags state fix(ExtraSidebar): add handleTagSelection function to handle tag selection in TagsSelector component fix(ExtraSidebar): update handleShareFlow function to pass selected tags and sharePublic value to saveFlowStore function fix(ExtraSidebar): update ConfirmationModal size prop to use size prop from component props fix(ExtraSidebar): update ConfirmationModal dependency array to include sharePublic value fix(NodeToolbarComponent): pass empty array as tags parameter to saveFlowStore function when sharing a component fix(MarketCardComponent): pass tags parameter to saveFlowStore function when saving a flow from the store fix(ConfirmationModal): add size prop to ConfirmationModalType to allow customizing the size of the modal
This commit is contained in:
parent
d34b551677
commit
cf434eb7ba
8 changed files with 132 additions and 14 deletions
26
src/frontend/src/components/tagsSelectorComponent/index.tsx
Normal file
26
src/frontend/src/components/tagsSelectorComponent/index.tsx
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
import TagComponent from "./tagComponent";
|
||||||
|
|
||||||
|
export function TagsSelector({
|
||||||
|
tags,
|
||||||
|
selectedTags,
|
||||||
|
setSelectedTags,
|
||||||
|
}: {
|
||||||
|
tags: string[];
|
||||||
|
selectedTags: Set<string>;
|
||||||
|
setSelectedTags: (tag: string) => void;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<div className=" flex h-full w-full flex-row flex-wrap gap-3 align-middle">
|
||||||
|
{tags.map((tag, index) => {
|
||||||
|
return (
|
||||||
|
<TagComponent
|
||||||
|
tag={tag}
|
||||||
|
selected={selectedTags.has(tag)}
|
||||||
|
key={index}
|
||||||
|
handleClick={setSelectedTags}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { useState } from "react";
|
||||||
|
import { Badge } from "../../ui/badge";
|
||||||
|
|
||||||
|
export default function TagComponent({
|
||||||
|
tag,
|
||||||
|
handleClick,
|
||||||
|
selected,
|
||||||
|
}: {
|
||||||
|
tag: string;
|
||||||
|
handleClick: (tag: string) => void;
|
||||||
|
selected: boolean;
|
||||||
|
}) {
|
||||||
|
const [selectedTag, setSelectedTag] = useState(selected);
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
setSelectedTag((prev) => !prev);
|
||||||
|
handleClick(tag);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Badge
|
||||||
|
size="md"
|
||||||
|
className={selectedTag ? "shadow-md" : ""}
|
||||||
|
variant={selectedTag ? "gray" : "secondary"}
|
||||||
|
>
|
||||||
|
{tag}
|
||||||
|
</Badge>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -547,14 +547,18 @@ export async function addApiKeyStore(key: string) {
|
||||||
* @returns {Promise<any>} The saved flow data.
|
* @returns {Promise<any>} The saved flow data.
|
||||||
* @throws Will throw an error if saving fails.
|
* @throws Will throw an error if saving fails.
|
||||||
*/
|
*/
|
||||||
export async function saveFlowStore(newFlow: {
|
export async function saveFlowStore(
|
||||||
|
newFlow: {
|
||||||
name?: string;
|
name?: string;
|
||||||
data: ReactFlowJsonObject | null;
|
data: ReactFlowJsonObject | null;
|
||||||
description?: string;
|
description?: string;
|
||||||
style?: FlowStyleType;
|
style?: FlowStyleType;
|
||||||
is_component?: boolean;
|
is_component?: boolean;
|
||||||
parent?: string;
|
parent?: string;
|
||||||
}): Promise<FlowType> {
|
},
|
||||||
|
tags: string[],
|
||||||
|
publicFlow = false
|
||||||
|
): Promise<FlowType> {
|
||||||
try {
|
try {
|
||||||
const response = await api.post(`${BASE_URL_API}store/components/`, {
|
const response = await api.post(`${BASE_URL_API}store/components/`, {
|
||||||
name: newFlow.name,
|
name: newFlow.name,
|
||||||
|
|
@ -562,6 +566,8 @@ export async function saveFlowStore(newFlow: {
|
||||||
description: newFlow.description,
|
description: newFlow.description,
|
||||||
is_component: newFlow.is_component,
|
is_component: newFlow.is_component,
|
||||||
parent: newFlow.parent,
|
parent: newFlow.parent,
|
||||||
|
tags: tags,
|
||||||
|
public: publicFlow,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.status !== 201) {
|
if (response.status !== 201) {
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ function ConfirmationModal({
|
||||||
data,
|
data,
|
||||||
index,
|
index,
|
||||||
onConfirm,
|
onConfirm,
|
||||||
|
size,
|
||||||
open,
|
open,
|
||||||
onClose,
|
onClose,
|
||||||
}: ConfirmationModalType) {
|
}: ConfirmationModalType) {
|
||||||
|
|
@ -50,7 +51,7 @@ function ConfirmationModal({
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BaseModal size="x-small" open={modalOpen} setOpen={setModalOpen}>
|
<BaseModal size={size ?? "x-small"} open={modalOpen} setOpen={setModalOpen}>
|
||||||
<BaseModal.Trigger asChild={asChild}>{triggerChild}</BaseModal.Trigger>
|
<BaseModal.Trigger asChild={asChild}>{triggerChild}</BaseModal.Trigger>
|
||||||
<BaseModal.Header description={titleHeader}>
|
<BaseModal.Header description={titleHeader}>
|
||||||
<span className="pr-2">{title}</span>
|
<span className="pr-2">{title}</span>
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ import { useContext, useEffect, useMemo, useState } from "react";
|
||||||
import { ReactFlowJsonObject } from "reactflow";
|
import { ReactFlowJsonObject } from "reactflow";
|
||||||
import ShadTooltip from "../../../../components/ShadTooltipComponent";
|
import ShadTooltip from "../../../../components/ShadTooltipComponent";
|
||||||
import IconComponent from "../../../../components/genericIconComponent";
|
import IconComponent from "../../../../components/genericIconComponent";
|
||||||
|
import { TagsSelector } from "../../../../components/tagsSelectorComponent";
|
||||||
|
import ToggleShadComponent from "../../../../components/toggleShadComponent";
|
||||||
import { Input } from "../../../../components/ui/input";
|
import { Input } from "../../../../components/ui/input";
|
||||||
import { Separator } from "../../../../components/ui/separator";
|
import { Separator } from "../../../../components/ui/separator";
|
||||||
import { alertContext } from "../../../../contexts/alertContext";
|
import { alertContext } from "../../../../contexts/alertContext";
|
||||||
|
|
@ -35,6 +37,7 @@ export default function ExtraSidebar(): JSX.Element {
|
||||||
const { setSuccessData, setErrorData } = useContext(alertContext);
|
const { setSuccessData, setErrorData } = useContext(alertContext);
|
||||||
const [dataFilter, setFilterData] = useState(data);
|
const [dataFilter, setFilterData] = useState(data);
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
|
const [sharePublic, setSharePublic] = useState(true);
|
||||||
const isPending = tabsState[tabId]?.isPending;
|
const isPending = tabsState[tabId]?.isPending;
|
||||||
function onDragStart(
|
function onDragStart(
|
||||||
event: React.DragEvent<any>,
|
event: React.DragEvent<any>,
|
||||||
|
|
@ -51,6 +54,26 @@ export default function ExtraSidebar(): JSX.Element {
|
||||||
event.dataTransfer.setData("nodedata", JSON.stringify(data));
|
event.dataTransfer.setData("nodedata", JSON.stringify(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const [tags, setTags] = useState<string[]>([]);
|
||||||
|
const [selectedTags, setSelectedTags] = useState<Set<string>>(new Set());
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
//TODO: get tags from api
|
||||||
|
setTags(["teste1", "teste2"]);
|
||||||
|
}, [setTags]);
|
||||||
|
|
||||||
|
function handleTagSelection(tag: string) {
|
||||||
|
setSelectedTags((prev) => {
|
||||||
|
const newSet = new Set(prev);
|
||||||
|
if (newSet.has(tag)) {
|
||||||
|
newSet.delete(tag);
|
||||||
|
} else {
|
||||||
|
newSet.add(tag);
|
||||||
|
}
|
||||||
|
return newSet;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Handle showing components after use search input
|
// Handle showing components after use search input
|
||||||
function handleSearchInput(e: string) {
|
function handleSearchInput(e: string) {
|
||||||
if (e === "") {
|
if (e === "") {
|
||||||
|
|
@ -116,7 +139,7 @@ export default function ExtraSidebar(): JSX.Element {
|
||||||
},
|
},
|
||||||
is_component: false,
|
is_component: false,
|
||||||
};
|
};
|
||||||
saveFlowStore(saveFlow).then(
|
saveFlowStore(saveFlow, Array.from(selectedTags), sharePublic).then(
|
||||||
() => {
|
() => {
|
||||||
setSuccessData({
|
setSuccessData({
|
||||||
title: "Flow shared successfully",
|
title: "Flow shared successfully",
|
||||||
|
|
@ -176,6 +199,7 @@ export default function ExtraSidebar(): JSX.Element {
|
||||||
title="Share Flow"
|
title="Share Flow"
|
||||||
confirmationText="Share"
|
confirmationText="Share"
|
||||||
icon="Share2"
|
icon="Share2"
|
||||||
|
size="smaller"
|
||||||
onConfirm={() => {
|
onConfirm={() => {
|
||||||
handleShareFlow();
|
handleShareFlow();
|
||||||
}}
|
}}
|
||||||
|
|
@ -183,7 +207,29 @@ export default function ExtraSidebar(): JSX.Element {
|
||||||
cancelText="Cancel"
|
cancelText="Cancel"
|
||||||
>
|
>
|
||||||
<ConfirmationModal.Content>
|
<ConfirmationModal.Content>
|
||||||
<span>This flow will be available for everyone to use.</span>
|
<div className="flex h-full w-full flex-col gap-7">
|
||||||
|
<div className="flex justify-start align-middle">
|
||||||
|
<ToggleShadComponent
|
||||||
|
disabled={false}
|
||||||
|
size="medium"
|
||||||
|
setEnabled={setSharePublic}
|
||||||
|
enabled={sharePublic}
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
{sharePublic
|
||||||
|
? "This flow will be avaliable for everyone"
|
||||||
|
: "This flow will be avaliable just for you"}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-full pt-2">
|
||||||
|
<span className="text-sm">Add some tags to your Flow</span>
|
||||||
|
<TagsSelector
|
||||||
|
tags={["teste1", "teste2"]}
|
||||||
|
selectedTags={new Set()}
|
||||||
|
setSelectedTags={handleTagSelection}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</ConfirmationModal.Content>
|
</ConfirmationModal.Content>
|
||||||
<ConfirmationModal.Trigger tolltipContent="Share" side="top">
|
<ConfirmationModal.Trigger tolltipContent="Share" side="top">
|
||||||
<div className={classNames("extra-side-bar-buttons")}>
|
<div className={classNames("extra-side-bar-buttons")}>
|
||||||
|
|
@ -192,7 +238,7 @@ export default function ExtraSidebar(): JSX.Element {
|
||||||
</ConfirmationModal.Trigger>
|
</ConfirmationModal.Trigger>
|
||||||
</ConfirmationModal>
|
</ConfirmationModal>
|
||||||
),
|
),
|
||||||
[]
|
[sharePublic]
|
||||||
);
|
);
|
||||||
|
|
||||||
const ExportMemo = useMemo(
|
const ExportMemo = useMemo(
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ export default function NodeToolbarComponent({
|
||||||
function handleShareComponent() {
|
function handleShareComponent() {
|
||||||
const componentFlow = cloneDeep(data);
|
const componentFlow = cloneDeep(data);
|
||||||
saveComponent(componentFlow).then(() => {
|
saveComponent(componentFlow).then(() => {
|
||||||
saveFlowStore(createFlowComponent(componentFlow)).then(
|
saveFlowStore(createFlowComponent(componentFlow), []).then(
|
||||||
(_) => {
|
(_) => {
|
||||||
setSuccessData({
|
setSuccessData({
|
||||||
title: "Component shared successfully",
|
title: "Component shared successfully",
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ export const MarketCardComponent = ({ data }: { data: storeComponent }) => {
|
||||||
const newFLow = cloneFLowWithParent(res, res.id, data.is_component);
|
const newFLow = cloneFLowWithParent(res, res.id, data.is_component);
|
||||||
flowData.current = newFLow;
|
flowData.current = newFLow;
|
||||||
console.log(newFLow);
|
console.log(newFLow);
|
||||||
saveFlowStore(newFLow)
|
saveFlowStore(newFLow, data.tags)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setAdded(true);
|
setAdded(true);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|
|
||||||
|
|
@ -298,6 +298,15 @@ export type ConfirmationModalType = {
|
||||||
onConfirm: (index, data) => void;
|
onConfirm: (index, data) => void;
|
||||||
open?: boolean;
|
open?: boolean;
|
||||||
onClose?: (close: boolean) => void;
|
onClose?: (close: boolean) => void;
|
||||||
|
size?:
|
||||||
|
| "x-small"
|
||||||
|
| "smaller"
|
||||||
|
| "small"
|
||||||
|
| "medium"
|
||||||
|
| "large"
|
||||||
|
| "large-h-full"
|
||||||
|
| "small-h-full"
|
||||||
|
| "medium-h-full";
|
||||||
};
|
};
|
||||||
|
|
||||||
export type UserManagementType = {
|
export type UserManagementType = {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue