Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion app/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
"@types/babel__standalone": "^7.1.7",
"@types/d3-geo": "^3.1.0",
"@types/google.maps": "^3.51.0",
"@types/react-beautiful-dnd": "^13.1.8",
"@types/react-page-visibility": "^6.4.1",
"@types/web": "^0.0.99",
"@uppy/core": "^1.16.0",
Expand Down Expand Up @@ -175,6 +176,7 @@
"rc-tree-select": "^5.4.0",
"react": "^17.0.2",
"react-append-to-body": "^2.0.26",
"react-beautiful-dnd": "^13.1.1",
"react-custom-scrollbars": "^4.2.1",
"react-device-detect": "^2.2.2",
"react-dnd": "^9.3.4",
Expand Down Expand Up @@ -227,7 +229,6 @@
"tinymce": "6.8.3",
"toposort": "^2.0.2",
"tslib": "^2.3.1",
"typescript": "^5.5.4",
"unescape-js": "^1.1.4",
"url-search-params-polyfill": "^8.0.0",
"usehooks-ts": "^3.1.0",
Expand Down Expand Up @@ -329,6 +330,7 @@
"eslint-plugin-sort-destructure-keys": "^1.5.0",
"eslint-plugin-storybook": "^0.6.15",
"eslint-plugin-testing-library": "^6.2.0",
"eslint-webpack-plugin": "^4.2.0",
"factory.ts": "^0.5.1",
"husky": "^8.0.0",
"jest": "^29.6.1",
Expand Down Expand Up @@ -359,6 +361,7 @@
"ts-jest": "^29.1.0",
"ts-jest-mock-import-meta": "^0.12.0",
"ts-node": "^10.9.1",
"typescript": "5.2.2",
"xlsx": "https://cdn.sheetjs.com/xlsx-0.19.3/xlsx-0.19.3.tgz"
},
"resolutions": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,14 @@ type PremiumDatasourceContactFormProps = PremiumDatasourceContactFormValues & {
formSyncErrors?: FormErrors<string, string>;
closeModal: () => void;
integrationName: string;
onSubmit?: () => void;
} & InjectedFormProps<
PremiumDatasourceContactFormValues,
{
formSyncErrors?: FormErrors<string, string>;
closeModal: () => void;
integrationName: string;
onSubmit?: () => void;
}
>;

Expand Down Expand Up @@ -166,6 +168,7 @@ export default connect((state: AppState) => {
formSyncErrors?: FormErrors<string, string>;
closeModal: () => void;
integrationName: string;
onSubmit?: () => void;
}
>({
validate,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export default function PremiumDatasources(props: {
<ContactForm
closeModal={() => setSelectedIntegration("")}
integrationName={selectedIntegration}
onSubmit={() => {}}
/>
</ModalContentWrapper>
</Modal>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,13 @@ interface RequestIntegrationFormValues {
type RequestIntegrationFormProps = RequestIntegrationFormValues & {
formSyncErrors?: FormErrors<string, string>;
closeModal: () => void;
onSubmit?: () => void;
} & InjectedFormProps<
RequestIntegrationFormValues,
{
formSyncErrors?: FormErrors<string, string>;
closeModal: () => void;
onSubmit?: () => void;
}
>;

Expand Down Expand Up @@ -146,6 +148,7 @@ export default connect((state: AppState) => {
{
formSyncErrors?: FormErrors<string, string>;
closeModal: () => void;
onSubmit?: () => void;
}
>({
validate,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ function RequestModal({ children }: { children: ReactNode }) {
<ModalHeader>
{createMessage(REQUEST_NEW_INTEGRATIONS.REQUEST_MODAL_HEADING)}
</ModalHeader>
<Form closeModal={() => setOpen(false)} />
<Form closeModal={() => setOpen(false)} onSubmit={() => {}} />
</ModalContentWrapper>
</Modal>
);
Expand Down
2 changes: 1 addition & 1 deletion app/client/src/pages/setup/UserWelcomeScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ const ActionContainer = styled.div`

interface LandingPageProps {
// To have a get started button click function for non super user form
onGetStarted?: (proficiency?: string, useCase?: string) => void;
onGetStarted?: ((proficiency?: string | undefined, useCase?: string | undefined) => void) | undefined;
// Property to determine whether the user is super admin or not
isSuperUser: boolean;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import type {
} from "deep-diff";
import { isEmpty, partition } from "lodash";

export function groupDifferencesByType(differences: Diff<unknown>[]): {
edits: DiffEdit<unknown, unknown>[];
additions: DiffNew<unknown>[];
deletions: DiffDeleted<unknown>[];
export function groupDifferencesByType(differences: Array<Diff<unknown>>): {
edits: Array<DiffEdit<unknown, unknown>>;
additions: Array<DiffNew<unknown>>;
deletions: Array<DiffDeleted<unknown>>;
} {
if (isEmpty(differences)) return { edits: [], additions: [], deletions: [] };

Expand Down
253 changes: 253 additions & 0 deletions app/client/src/widgets/KanbanBoardWidget/component/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
import React from "react";
import styled from "styled-components";
import type {
DropResult,
DroppableProvided,
DroppableStateSnapshot,
DraggableProvided,
DraggableStateSnapshot,
} from "react-beautiful-dnd";
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";

export interface KanbanTask {
title: string;
description: string;
style?: {
backgroundColor?: string;
textColor?: string;
};
}

export interface KanbanColumn {
title: string;
tasks: KanbanTask[];
style?: {
backgroundColor?: string;
textColor?: string;
};
}

interface KanbanComponentProps {
columns: KanbanColumn[];
backgroundColor?: string;
borderRadius?: string;
boxShadow?: string;
onTaskMove?: (columns: KanbanColumn[]) => void;
}

const Container = styled.div<{
backgroundColor?: string;
borderRadius?: string;
boxShadow?: string;
}>`
display: flex;
height: 100%;
background-color: ${(props) =>
props.backgroundColor || "var(--appsmith-color-black-0)"};
border-radius: ${(props) =>
props.borderRadius || "var(--appsmith-border-radius-1)"};
box-shadow: ${(props) => props.boxShadow || "none"};
padding: var(--appsmith-spaces-4);
gap: var(--appsmith-spaces-4);
overflow-x: auto;
font-family: var(--appsmith-font-family);
`;

const Column = styled.div<{
backgroundColor?: string;
textColor?: string;
}>`
background-color: ${(props) =>
props.backgroundColor || "var(--appsmith-color-black-50)"};
border-radius: var(--appsmith-border-radius-1);
width: 280px;
min-width: 280px;
display: flex;
flex-direction: column;
padding: var(--appsmith-spaces-4);
`;

const ColumnTitle = styled.h3`
margin: 0;
padding: var(--appsmith-spaces-4);
font-size: var(--appsmith-font-size-4);
font-weight: var(--appsmith-font-weight-5);
color: ${(props) => props.color || "var(--appsmith-color-black-900)"};
`;

const TaskList = styled.div`
padding: var(--appsmith-spaces-4);
flex-grow: 1;
min-height: 100px;
transition: background-color 0.2s ease;

&.dragging-over {
background-color: var(--appsmith-color-black-100);
border-radius: var(--appsmith-border-radius-1);
}
`;

const Task = styled.div<{
backgroundColor?: string;
textColor?: string;
}>`
background-color: ${(props) =>
props.backgroundColor || "var(--appsmith-color-black-0)"};
color: ${(props) => props.textColor || "var(--appsmith-color-black-800)"};
border-radius: var(--appsmith-border-radius-1);
padding: var(--appsmith-spaces-4);
margin-bottom: var(--appsmith-spaces-3);
box-shadow: var(--appsmith-card-shadow);
cursor: grab;
transition:
transform 0.2s ease,
box-shadow 0.2s ease;

&:hover {
transform: translateY(-2px);
box-shadow: var(--appsmith-card-shadow-hover);
}

&:active {
cursor: grabbing;
}
`;

const TaskTitle = styled.div`
font-weight: var(--appsmith-font-weight-5);
margin-bottom: var(--appsmith-spaces-2);
color: inherit;
`;

const TaskDescription = styled.div`
font-size: var(--appsmith-font-size-3);
color: inherit;
opacity: 0.8;
`;

const KanbanComponent: React.FC<KanbanComponentProps> = React.memo(
({
backgroundColor,
borderRadius,
boxShadow,
columns,
onTaskMove,
}: KanbanComponentProps) => {
const onDragEnd = React.useCallback(
(result: DropResult): void => {
const { destination, source } = result;

if (!destination) return;

if (
destination.droppableId === source.droppableId &&
destination.index === source.index
) {
return;
}

const sourceColumnIndex = parseInt(source.droppableId.split("-")[1]);
const destColumnIndex = parseInt(destination.droppableId.split("-")[1]);

const newColumns = [...columns];
const sourceColumn = newColumns[sourceColumnIndex];
const destColumn = newColumns[destColumnIndex];

const [movedTask] = sourceColumn.tasks.splice(source.index, 1);

destColumn.tasks.splice(destination.index, 0, movedTask);

// Trigger widget property update
if (onTaskMove) {
onTaskMove(newColumns);
}
},
[columns, onTaskMove],
);

return (
<Container
backgroundColor={backgroundColor}
borderRadius={borderRadius}
boxShadow={boxShadow}
>
<DragDropContext onDragEnd={onDragEnd}>
{columns.map((column, columnIndex) => (
<Column
backgroundColor={column.style?.backgroundColor ?? undefined}
key={columnIndex}
textColor={column.style?.textColor ?? undefined}
>
<ColumnTitle color={column.style?.textColor ?? undefined}>
{column.title}
</ColumnTitle>
<Droppable droppableId={`column-${columnIndex}`}>
{(
provided: DroppableProvided,
snapshot: DroppableStateSnapshot,
) => (
<TaskList
ref={provided.innerRef}
{...provided.droppableProps}
className={snapshot.isDraggingOver ? "dragging-over" : ""}
data-testid="t--kanban-tasklist"
>
{column.tasks.map((task, taskIndex) => (
<Draggable
draggableId={`task-${columnIndex}-${taskIndex}`}
index={taskIndex}
key={taskIndex}
>
{(
provided: DraggableProvided,
snapshot: DraggableStateSnapshot,
) => (
<Task
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
backgroundColor={
task.style?.backgroundColor ?? undefined
}
data-testid="t--kanban-task"
style={React.useMemo(
() => ({
...provided.draggableProps.style,
transform:
snapshot.isDragging &&
provided.draggableProps.style
? provided.draggableProps.style.transform ??
"none"
: "none",
backgroundColor: task.style?.backgroundColor,
color: task.style?.textColor,
}),
[
provided.draggableProps.style,
snapshot.isDragging,
task.style,
],
)}
textColor={task.style?.textColor ?? undefined}
>
<TaskTitle>{task.title}</TaskTitle>
<TaskDescription>
{task.description}
</TaskDescription>
</Task>
)}
</Draggable>
))}
{provided.placeholder}
</TaskList>
)}
</Droppable>
</Column>
))}
</DragDropContext>
</Container>
);
},
);

export default KanbanComponent;
12 changes: 12 additions & 0 deletions app/client/src/widgets/KanbanBoardWidget/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export const KANBAN_BOARD_WIDGET = "KANBAN_BOARD_WIDGET";

export const DefaultColumnStyles = {
backgroundColor: "#F4F4F4",
borderRadius: "4px",
};

export const DefaultTaskStyles = {
backgroundColor: "#FFFFFF",
borderRadius: "4px",
boxShadow: "0 1px 3px rgba(0, 0, 0, 0.1)",
};
5 changes: 5 additions & 0 deletions app/client/src/widgets/KanbanBoardWidget/icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading