✨ (tableComponent): add editable prop to TableComponent for column editing
✨ (API): add updateMessageApi function to update messages via API ✨ (chatView): add select dropdown for clearing builds and sessions ♻️ (use-messages-table): refactor to use messages store for setting messages ♻️ (use-remove-messages): remove setRows and use messages store for deletion ✨ (use-updateMessage): add hook for updating messages with API integration 📝 (headerMessages): update header message text in messages page ✨ (messagesPage): add cell edit request handling for message updates ♻️ (messagesPage): refactor state management and hooks usage ✨ (types): add new types for chat and message handling
This commit is contained in:
commit
93568b4c0d
12 changed files with 161 additions and 39 deletions
|
|
@ -321,4 +321,3 @@ class FlowDataRequest(BaseModel):
|
||||||
|
|
||||||
class ConfigResponse(BaseModel):
|
class ConfigResponse(BaseModel):
|
||||||
frontend_timeout: int
|
frontend_timeout: int
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ interface TableComponentProps extends AgGridReactProps {
|
||||||
rowData: NonNullable<AgGridReactProps["rowData"]>;
|
rowData: NonNullable<AgGridReactProps["rowData"]>;
|
||||||
alertTitle?: string;
|
alertTitle?: string;
|
||||||
alertDescription?: string;
|
alertDescription?: string;
|
||||||
|
editable?: boolean | string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const TableComponent = forwardRef<
|
const TableComponent = forwardRef<
|
||||||
|
|
@ -48,20 +49,29 @@ const TableComponent = forwardRef<
|
||||||
}
|
}
|
||||||
|
|
||||||
const colDef = props.columnDefs.map((col, index) => {
|
const colDef = props.columnDefs.map((col, index) => {
|
||||||
if (props.onSelectionChanged && index === 0) {
|
let newCol = {
|
||||||
return {
|
|
||||||
...col,
|
...col,
|
||||||
headerName: toTitleCase(col.headerName),
|
headerName: toTitleCase(col.headerName),
|
||||||
|
};
|
||||||
|
if (props.onSelectionChanged && index === 0) {
|
||||||
|
newCol = {
|
||||||
|
...newCol,
|
||||||
checkboxSelection: true,
|
checkboxSelection: true,
|
||||||
headerCheckboxSelection: true,
|
headerCheckboxSelection: true,
|
||||||
headerCheckboxSelectionFilteredOnly: true,
|
headerCheckboxSelectionFilteredOnly: true,
|
||||||
};
|
};
|
||||||
} else {
|
}
|
||||||
return {
|
if (
|
||||||
...col,
|
(typeof props.editable === "boolean" && props.editable) ||
|
||||||
headerName: toTitleCase(col.headerName),
|
(Array.isArray(props.editable) &&
|
||||||
|
props.editable.includes(newCol.headerName ?? ""))
|
||||||
|
) {
|
||||||
|
newCol = {
|
||||||
|
...newCol,
|
||||||
|
editable: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
return newCol;
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import {
|
||||||
UploadFileTypeAPI,
|
UploadFileTypeAPI,
|
||||||
errorsTypeAPI,
|
errorsTypeAPI,
|
||||||
} from "./../../types/api/index";
|
} from "./../../types/api/index";
|
||||||
|
import { Message } from "../../types/messages";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches all objects from the API endpoint.
|
* Fetches all objects from the API endpoint.
|
||||||
|
|
@ -1049,3 +1050,7 @@ export async function deleteMessagesFn(ids: number[]) {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function updateMessageApi(data: Message) {
|
||||||
|
return await api.post(`${BASE_URL_API}monitor/messages/${data.index}`, data);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,12 @@ import { chatViewProps } from "../../../../types/components";
|
||||||
import { classNames } from "../../../../utils/utils";
|
import { classNames } from "../../../../utils/utils";
|
||||||
import ChatInput from "./chatInput";
|
import ChatInput from "./chatInput";
|
||||||
import ChatMessage from "./chatMessage";
|
import ChatMessage from "./chatMessage";
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
} from "../../../../components/ui/select";
|
||||||
|
|
||||||
export default function ChatView({
|
export default function ChatView({
|
||||||
sendMessage,
|
sendMessage,
|
||||||
|
|
@ -118,10 +124,21 @@ export default function ChatView({
|
||||||
if (lockChat) setLockChat(false);
|
if (lockChat) setLockChat(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleSelectChange(event: string): void {
|
||||||
|
switch (event) {
|
||||||
|
case "builds":
|
||||||
|
clearChat();
|
||||||
|
break;
|
||||||
|
case "buildsNSession":
|
||||||
|
console.log("delete build and session");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function updateChat(
|
function updateChat(
|
||||||
chat: ChatMessageType,
|
chat: ChatMessageType,
|
||||||
message: string,
|
message: string,
|
||||||
stream_url?: string
|
stream_url?: string,
|
||||||
) {
|
) {
|
||||||
// if (message === "") return;
|
// if (message === "") return;
|
||||||
chat.message = message;
|
chat.message = message;
|
||||||
|
|
@ -149,18 +166,44 @@ export default function ChatView({
|
||||||
<div className="eraser-column-arrangement">
|
<div className="eraser-column-arrangement">
|
||||||
<div className="eraser-size">
|
<div className="eraser-size">
|
||||||
<div className="eraser-position">
|
<div className="eraser-position">
|
||||||
<button disabled={lockChat} onClick={() => clearChat()}>
|
<Select
|
||||||
|
onValueChange={handleSelectChange}
|
||||||
|
value=""
|
||||||
|
disabled={lockChat}
|
||||||
|
>
|
||||||
|
<SelectTrigger className="">
|
||||||
|
<button className="flex gap-1">
|
||||||
<IconComponent
|
<IconComponent
|
||||||
name="Eraser"
|
name="Eraser"
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"h-5 w-5",
|
"h-5 w-5 transition-all duration-100",
|
||||||
lockChat
|
lockChat ? "animate-pulse text-primary" : "text-primary",
|
||||||
? "animate-pulse text-primary"
|
|
||||||
: "text-primary hover:text-gray-600"
|
|
||||||
)}
|
)}
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent className="right-[9.5em]">
|
||||||
|
<SelectItem value="builds" className="cursor-pointer">
|
||||||
|
<div className="flex">
|
||||||
|
<IconComponent
|
||||||
|
name={"Trash2"}
|
||||||
|
className={`relative top-0.5 mr-2 h-4 w-4`}
|
||||||
|
/>
|
||||||
|
<span className="">Clear Builds</span>
|
||||||
|
</div>
|
||||||
|
</SelectItem>
|
||||||
|
<SelectItem value="buildsNSession" className="cursor-pointer">
|
||||||
|
<div className="flex">
|
||||||
|
<IconComponent
|
||||||
|
name={"Trash2"}
|
||||||
|
className={`relative top-0.5 mr-2 h-4 w-4`}
|
||||||
|
/>
|
||||||
|
<span className="">Clear Builds & Session</span>
|
||||||
|
</div>
|
||||||
|
</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
<div ref={messagesRef} className="chat-message-div">
|
<div ref={messagesRef} className="chat-message-div">
|
||||||
{chatHistory?.length > 0 ? (
|
{chatHistory?.length > 0 ? (
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,7 @@ const HeaderMessagesComponent = ({
|
||||||
className="ml-2 h-5 w-5 text-primary"
|
className="ml-2 h-5 w-5 text-primary"
|
||||||
/>
|
/>
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">@Rodrigo</p>
|
||||||
Manage your messages as you like.
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-shrink-0 items-center gap-2">
|
<div className="flex flex-shrink-0 items-center gap-2">
|
||||||
<Button
|
<Button
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,15 @@
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { getMessagesTable } from "../../../../../controllers/API";
|
import { getMessagesTable } from "../../../../../controllers/API";
|
||||||
|
import { useMessagesStore } from "../../../../../stores/messagesStore";
|
||||||
|
|
||||||
const useMessagesTable = (setColumns, setRows, setMessages) => {
|
const useMessagesTable = (setColumns) => {
|
||||||
|
const setMessages = useMessagesStore((state) => state.setMessages);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
try {
|
try {
|
||||||
const data = await getMessagesTable("union", undefined, ["index"]);
|
const data = await getMessagesTable("union", undefined, ["index"]);
|
||||||
const { columns, rows } = data;
|
const { columns, rows } = data;
|
||||||
setColumns(columns.map((col) => ({ ...col, editable: true })));
|
setColumns(columns);
|
||||||
setRows(rows);
|
|
||||||
setMessages(rows);
|
setMessages(rows);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching messages:", error);
|
console.error("Error fetching messages:", error);
|
||||||
|
|
|
||||||
|
|
@ -2,19 +2,17 @@ import { deleteMessagesFn } from "../../../../../controllers/API";
|
||||||
import { useMessagesStore } from "../../../../../stores/messagesStore";
|
import { useMessagesStore } from "../../../../../stores/messagesStore";
|
||||||
|
|
||||||
const useRemoveMessages = (
|
const useRemoveMessages = (
|
||||||
setRows,
|
|
||||||
setSelectedRows,
|
setSelectedRows,
|
||||||
setSuccessData,
|
setSuccessData,
|
||||||
setErrorData,
|
setErrorData,
|
||||||
selectedRows,
|
selectedRows
|
||||||
) => {
|
) => {
|
||||||
const deleteMessages = useMessagesStore((state) => state.removeMessages);
|
const deleteMessages = useMessagesStore((state) => state.removeMessages);
|
||||||
|
|
||||||
const handleRemoveMessages = async () => {
|
const handleRemoveMessages = async () => {
|
||||||
try {
|
try {
|
||||||
await deleteMessagesFn(selectedRows);
|
await deleteMessagesFn(selectedRows);
|
||||||
const res = await deleteMessages(selectedRows);
|
deleteMessages(selectedRows);
|
||||||
setRows(res);
|
|
||||||
setSelectedRows([]);
|
setSelectedRows([]);
|
||||||
setSuccessData({
|
setSuccessData({
|
||||||
title: "Messages deleted successfully.",
|
title: "Messages deleted successfully.",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { useMessagesStore } from "../../../../../stores/messagesStore";
|
||||||
|
import { Message } from "../../../../../types/messages";
|
||||||
|
import { updateMessageApi } from "../../../../../controllers/API";
|
||||||
|
|
||||||
|
const useUpdateMessage = (setSuccessData, setErrorData) => {
|
||||||
|
const updateMessage = useMessagesStore((state) => state.updateMessage);
|
||||||
|
|
||||||
|
const handleUpdate = async (data: Message) => {
|
||||||
|
try {
|
||||||
|
await updateMessageApi(data);
|
||||||
|
|
||||||
|
updateMessage(data);
|
||||||
|
|
||||||
|
// Set success message
|
||||||
|
setSuccessData({
|
||||||
|
title: "Messages updated successfully.",
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
// Set error message
|
||||||
|
setErrorData({
|
||||||
|
title: "Error updating messages.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return { handleUpdate };
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useUpdateMessage;
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
import { ColDef, ColGroupDef, SelectionChangedEvent } from "ag-grid-community";
|
import {
|
||||||
|
CellEditRequestEvent,
|
||||||
|
ColDef,
|
||||||
|
ColGroupDef,
|
||||||
|
SelectionChangedEvent,
|
||||||
|
} from "ag-grid-community";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import TableComponent from "../../../../components/tableComponent";
|
import TableComponent from "../../../../components/tableComponent";
|
||||||
import { Card, CardContent } from "../../../../components/ui/card";
|
import { Card, CardContent } from "../../../../components/ui/card";
|
||||||
|
|
@ -7,12 +12,11 @@ import { useMessagesStore } from "../../../../stores/messagesStore";
|
||||||
import HeaderMessagesComponent from "./components/headerMessages";
|
import HeaderMessagesComponent from "./components/headerMessages";
|
||||||
import useMessagesTable from "./hooks/use-messages-table";
|
import useMessagesTable from "./hooks/use-messages-table";
|
||||||
import useRemoveMessages from "./hooks/use-remove-messages";
|
import useRemoveMessages from "./hooks/use-remove-messages";
|
||||||
|
import useUpdateMessage from "./hooks/use-updateMessage";
|
||||||
|
|
||||||
export default function MessagesPage() {
|
export default function MessagesPage() {
|
||||||
const setMessages = useMessagesStore((state) => state.setMessages);
|
|
||||||
|
|
||||||
const [columns, setColumns] = useState<Array<ColDef | ColGroupDef>>([]);
|
const [columns, setColumns] = useState<Array<ColDef | ColGroupDef>>([]);
|
||||||
const [rows, setRows] = useState<any>([]);
|
const messages = useMessagesStore((state) => state.messages);
|
||||||
|
|
||||||
const setErrorData = useAlertStore((state) => state.setErrorData);
|
const setErrorData = useAlertStore((state) => state.setErrorData);
|
||||||
const setSuccessData = useAlertStore((state) => state.setSuccessData);
|
const setSuccessData = useAlertStore((state) => state.setSuccessData);
|
||||||
|
|
@ -20,14 +24,26 @@ export default function MessagesPage() {
|
||||||
const [selectedRows, setSelectedRows] = useState<number[]>([]);
|
const [selectedRows, setSelectedRows] = useState<number[]>([]);
|
||||||
|
|
||||||
const { handleRemoveMessages } = useRemoveMessages(
|
const { handleRemoveMessages } = useRemoveMessages(
|
||||||
setRows,
|
|
||||||
setSelectedRows,
|
setSelectedRows,
|
||||||
setSuccessData,
|
setSuccessData,
|
||||||
setErrorData,
|
setErrorData,
|
||||||
selectedRows,
|
selectedRows,
|
||||||
);
|
);
|
||||||
|
|
||||||
useMessagesTable(setColumns, setRows, setMessages);
|
const { handleUpdate } = useUpdateMessage(setSuccessData, setErrorData);
|
||||||
|
|
||||||
|
useMessagesTable(setColumns);
|
||||||
|
|
||||||
|
function handleUpdateMessage(event: CellEditRequestEvent<any, string>) {
|
||||||
|
const newValue = event.newValue;
|
||||||
|
const field = event.column.getColId();
|
||||||
|
const row = event.data;
|
||||||
|
const data = {
|
||||||
|
...row,
|
||||||
|
[field]: newValue,
|
||||||
|
};
|
||||||
|
handleUpdate(data);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full w-full flex-col justify-between gap-6">
|
<div className="flex h-full w-full flex-col justify-between gap-6">
|
||||||
|
|
@ -40,6 +56,11 @@ export default function MessagesPage() {
|
||||||
<Card x-chunk="dashboard-04-chunk-2" className="h-full pt-4">
|
<Card x-chunk="dashboard-04-chunk-2" className="h-full pt-4">
|
||||||
<CardContent className="h-full">
|
<CardContent className="h-full">
|
||||||
<TableComponent
|
<TableComponent
|
||||||
|
readOnlyEdit
|
||||||
|
onCellEditRequest={(event) => {
|
||||||
|
handleUpdateMessage(event);
|
||||||
|
}}
|
||||||
|
editable={["Sender", "Sender Name", "Message"]}
|
||||||
overlayNoRowsTemplate="No data available"
|
overlayNoRowsTemplate="No data available"
|
||||||
onSelectionChanged={(event: SelectionChangedEvent) => {
|
onSelectionChanged={(event: SelectionChangedEvent) => {
|
||||||
setSelectedRows(
|
setSelectedRows(
|
||||||
|
|
@ -50,7 +71,7 @@ export default function MessagesPage() {
|
||||||
suppressRowClickSelection={true}
|
suppressRowClickSelection={true}
|
||||||
pagination={true}
|
pagination={true}
|
||||||
columnDefs={columns}
|
columnDefs={columns}
|
||||||
rowData={rows}
|
rowData={messages}
|
||||||
/>
|
/>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
|
||||||
|
|
@ -752,3 +752,17 @@ export type toolbarSelectItemProps = {
|
||||||
dataTestId: string;
|
dataTestId: string;
|
||||||
ping?: boolean;
|
ping?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type clearChatPropsType = {
|
||||||
|
lockChat: boolean;
|
||||||
|
setLockChat: (lock: boolean) => void;
|
||||||
|
setChatHistory: (chatHistory: ChatMessageType) => void;
|
||||||
|
method: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type handleSelectPropsType = {
|
||||||
|
event: string;
|
||||||
|
lockChat: boolean;
|
||||||
|
setLockChat: (lock: boolean) => void;
|
||||||
|
setChatHistory: (chatHistory: ChatMessageType) => void;
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -9,3 +9,5 @@ type Message = {
|
||||||
timestamp: string;
|
timestamp: string;
|
||||||
id: string;
|
id: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type { Message };
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { Message } from "../../messages";
|
||||||
|
|
||||||
export type MessagesStoreType = {
|
export type MessagesStoreType = {
|
||||||
messages: Message[];
|
messages: Message[];
|
||||||
setMessages: (messages: Message[]) => void;
|
setMessages: (messages: Message[]) => void;
|
||||||
|
|
@ -5,5 +7,5 @@ export type MessagesStoreType = {
|
||||||
removeMessage: (message: Message) => void;
|
removeMessage: (message: Message) => void;
|
||||||
updateMessage: (message: Message) => void;
|
updateMessage: (message: Message) => void;
|
||||||
clearMessages: () => void;
|
clearMessages: () => void;
|
||||||
removeMessages: (ids: number[]) => Promise<Message[]>;
|
removeMessages: (ids: number[]) => void;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue