diff --git a/src/backend/base/langflow/alembic/versions/1f4d6df60295_add_default_fields_column.py b/src/backend/base/langflow/alembic/versions/1f4d6df60295_add_default_fields_column.py new file mode 100644 index 000000000..7b69058c2 --- /dev/null +++ b/src/backend/base/langflow/alembic/versions/1f4d6df60295_add_default_fields_column.py @@ -0,0 +1,45 @@ +"""Add default_fields column + +Revision ID: 1f4d6df60295 +Revises: 58b28437a398 +Create Date: 2024-04-29 09:49:46.864145 + +""" + +from typing import Sequence, Union + +import sqlalchemy as sa +from alembic import op +from sqlalchemy.engine.reflection import Inspector + +# revision identifiers, used by Alembic. +revision: str = "1f4d6df60295" +down_revision: Union[str, None] = "58b28437a398" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + conn = op.get_bind() + inspector = Inspector.from_engine(conn) # type: ignore + table_names = inspector.get_table_names() + # ### commands auto generated by Alembic - please adjust! ### + column_names = [column["name"] for column in inspector.get_columns("variable")] + with op.batch_alter_table("variable", schema=None) as batch_op: + if "default_fields" not in column_names: + batch_op.add_column(sa.Column("default_fields", sa.JSON(), nullable=True)) + + # ### end Alembic commands ### + + +def downgrade() -> None: + conn = op.get_bind() + inspector = Inspector.from_engine(conn) # type: ignore + table_names = inspector.get_table_names() + # ### commands auto generated by Alembic - please adjust! ### + column_names = [column["name"] for column in inspector.get_columns("variable")] + with op.batch_alter_table("variable", schema=None) as batch_op: + if "default_fields" in column_names: + batch_op.drop_column("default_fields") + + # ### end Alembic commands ### diff --git a/src/backend/base/langflow/api/v1/variable.py b/src/backend/base/langflow/api/v1/variable.py index 123086676..b1cca14c1 100644 --- a/src/backend/base/langflow/api/v1/variable.py +++ b/src/backend/base/langflow/api/v1/variable.py @@ -1,4 +1,4 @@ -from datetime import datetime +from datetime import datetime, timezone from uuid import UUID from fastapi import APIRouter, Depends, HTTPException @@ -85,7 +85,7 @@ def update_variable( variable_data = variable.model_dump(exclude_unset=True) for key, value in variable_data.items(): setattr(db_variable, key, value) - db_variable.updated_at = datetime.utcnow() + db_variable.updated_at = datetime.now(timezone.utc) session.commit() session.refresh(db_variable) return db_variable diff --git a/src/backend/base/langflow/services/database/models/variable/model.py b/src/backend/base/langflow/services/database/models/variable/model.py index 1fab92b4c..cf2236fe1 100644 --- a/src/backend/base/langflow/services/database/models/variable/model.py +++ b/src/backend/base/langflow/services/database/models/variable/model.py @@ -1,8 +1,8 @@ from datetime import datetime, timezone -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING, List, Optional from uuid import UUID, uuid4 -from sqlmodel import Column, DateTime, Field, Relationship, SQLModel, func +from sqlmodel import JSON, Column, DateTime, Field, Relationship, SQLModel, func if TYPE_CHECKING: from langflow.services.database.models.user.model import User @@ -15,6 +15,7 @@ def utc_now(): class VariableBase(SQLModel): name: Optional[str] = Field(None, description="Name of the variable") value: Optional[str] = Field(None, description="Encrypted value of the variable") + default_fields: Optional[List[str]] = Field(sa_column=Column(JSON)) type: Optional[str] = Field(None, description="Type of the variable") @@ -35,6 +36,7 @@ class Variable(VariableBase, table=True): sa_column=Column(DateTime(timezone=True), nullable=True), description="Last update time of the variable", ) + default_fields: Optional[List[str]] = Field(sa_column=Column(JSON)) # foreign key to user table user_id: UUID = Field(description="User ID associated with this variable", foreign_key="user.id") user: "User" = Relationship(back_populates="variables") @@ -56,3 +58,4 @@ class VariableUpdate(SQLModel): id: UUID # Include the ID for updating name: Optional[str] = Field(None, description="Name of the variable") value: Optional[str] = Field(None, description="Encrypted value of the variable") + default_fields: Optional[List[str]] = Field(None, description="Default fields for the variable") diff --git a/src/frontend/src/components/tableComponent/index.tsx b/src/frontend/src/components/tableComponent/index.tsx index 754cc4dda..43a9106b1 100644 --- a/src/frontend/src/components/tableComponent/index.tsx +++ b/src/frontend/src/components/tableComponent/index.tsx @@ -1,18 +1,18 @@ +import { ColDef, ColGroupDef } from "ag-grid-community"; import "ag-grid-community/styles/ag-grid.css"; // Mandatory CSS required by the grid import "ag-grid-community/styles/ag-theme-quartz.css"; // Optional Theme applied to the grid import { AgGridReact } from "ag-grid-react"; import { ColDef,ColGroupDef } from 'ag-grid-community'; import { useState } from "react"; -import { Card, CardContent, CardFooter } from "../ui/card"; +import { useDarkStore } from "../../stores/darkStore"; +import "../../style/ag-theme-shadcn.css"; // Custom CSS applied to the grid +import { cn } from "../../utils/utils"; +import { Button } from "../ui/button"; export default function TableComponent() { // Column Definitions: Defines the columns to be displayed. const [colDefs, setColDefs] = useState<(ColDef | ColGroupDef)[]>([ - { headerName: "Variable Name", - field: "name", - flex: 1, - editable: true - }, //This column will be twice as wide as the others + { headerName: "Variable Name", field: "name", flex: 1 }, //This column will be twice as wide as the others { field: "type", @@ -32,7 +32,7 @@ export default function TableComponent() { editable: true, }, { - headerName: "Default Fields", + headerName: "Apply To Fields", field: "defaultFields", flex: 1, editable: true, @@ -72,20 +72,18 @@ export default function TableComponent() { }, ]); + const dark = useDarkStore((state) => state.dark); + return ( - - +
- +
- - -
- Showing 1-3 of 3 products -
-
- +
); } diff --git a/src/frontend/src/pages/GlobalVariablesPage/index.tsx b/src/frontend/src/pages/GlobalVariablesPage/index.tsx index 41e72bcc0..5d3b3a981 100644 --- a/src/frontend/src/pages/GlobalVariablesPage/index.tsx +++ b/src/frontend/src/pages/GlobalVariablesPage/index.tsx @@ -1,6 +1,8 @@ import IconComponent from "../../components/genericIconComponent"; import { Button } from "../../components/ui/button"; +import AddNewVariableButton from "../../components/addNewVariableButtonComponent/addNewVariableButton"; +import ForwardedIconComponent from "../../components/genericIconComponent"; import TableComponent from "../../components/tableComponent"; export default function GlobalVariablesPage() { @@ -8,17 +10,25 @@ export default function GlobalVariablesPage() {
-

Global Variables

-

+

+ Global Variables + +

+

Manage and assign global variables to default fields. You can add new global variables by clicking the button.

- + + +
diff --git a/src/frontend/src/stores/globalVariables.ts b/src/frontend/src/stores/globalVariables.ts index e2f3e37df..6cbb8a641 100644 --- a/src/frontend/src/stores/globalVariables.ts +++ b/src/frontend/src/stores/globalVariables.ts @@ -3,6 +3,13 @@ import { GlobalVariablesStore } from "../types/zustand/globalVariables"; export const useGlobalVariablesStore = create( (set, get) => ({ + avaliableFields: [], + setAvaliableFields: (fields) => { + set({ avaliableFields: fields }); + }, + addAvaliableField: (field) => { + set({ avaliableFields: [...get().avaliableFields, field] }); + }, globalVariablesEntries: [], globalVariables: {}, setGlobalVariables: (variables) => { diff --git a/src/frontend/src/stores/typesStore.ts b/src/frontend/src/stores/typesStore.ts index 142118f44..95223087f 100644 --- a/src/frontend/src/stores/typesStore.ts +++ b/src/frontend/src/stores/typesStore.ts @@ -24,6 +24,7 @@ export const useTypesStore = create((set, get) => ({ templates: templatesGenerator(data), })); setLoading(false); + console.log(templatesGenerator(data)) resolve(); }) .catch((error) => { diff --git a/src/frontend/src/style/ag-theme-shadcn.css b/src/frontend/src/style/ag-theme-shadcn.css new file mode 100644 index 000000000..3605d53b3 --- /dev/null +++ b/src/frontend/src/style/ag-theme-shadcn.css @@ -0,0 +1,21 @@ +/* set the background color of many elements across the grid */ +.ag-theme-shadcn { + --ag-foreground-color: hsl(var(--foreground)); + --ag-background-color: hsl(var(--background)); + --ag-secondary-foreground-color: hsl(var(--secondary-foreground)); + --ag-data-color: hsl(var(--foreground)); + --ag-header-foreground-color: hsl(var(--muted-foreground)); + --ag-header-background-color: hsl(var(--background)); + --ag-tooltip-background-color: hsl(var(--muted)); + --ag-disabled-foreground-color: hsl(var(--muted-foreground)); + --ag-border-color: hsl(var(--border)); + --ag-selected-row-background-color: hsl(var(--accent)); + --ag-menu-background-color: hsl(var(--accent)); + --ag-panel-background-color: hsl(var(--accent)); + --ag-row-hover-color: hsl(var(--accent)); + --ag-header-height: 2.5rem; +} + +.ag-theme-shadcn .ag-paging-panel { + height: 3rem; +} diff --git a/src/frontend/src/types/zustand/globalVariables/index.ts b/src/frontend/src/types/zustand/globalVariables/index.ts index 3e651179e..fbf7f0675 100644 --- a/src/frontend/src/types/zustand/globalVariables/index.ts +++ b/src/frontend/src/types/zustand/globalVariables/index.ts @@ -7,4 +7,7 @@ export type GlobalVariablesStore = { addGlobalVariable: (name: string, id: string, type?: string) => void; removeGlobalVariable: (name: string) => void; getVariableId: (name: string) => string | undefined; + avaliableFields: Array; + setAvaliableFields: (fields: Array) => void; + addAvaliableField: (field: string) => void; }; diff --git a/src/frontend/src/utils/reactflowUtils.ts b/src/frontend/src/utils/reactflowUtils.ts index 4cd19bf7e..49aae5b7a 100644 --- a/src/frontend/src/utils/reactflowUtils.ts +++ b/src/frontend/src/utils/reactflowUtils.ts @@ -1234,6 +1234,19 @@ export function templatesGenerator(data: APIObjectType) { }, {}); } +export function extractFieldsFromComponenents(data:APIObjectType ) { + const fields = new Set(); + Object.keys(data).forEach((key) => { + Object.keys(data[key]).forEach((kind) => { + Object.keys(data[key][kind].template).forEach((field) => { + if(data[key][kind].template[field].display_name && data[key][kind].template[field].show) + fields.add(data[key][kind].template[field].display_name); + }); + }); + }); + return Array.from(fields); +} + export function downloadFlow( flow: FlowType, flowName: string,