Skip to content
This repository has been archived by the owner on Jan 5, 2025. It is now read-only.

Commit

Permalink
Merge pull request #438 from openchatai/ui/copilot-styling-api
Browse files Browse the repository at this point in the history
UI Changes on the Dashboard and Copilot widget
  • Loading branch information
faltawy authored Dec 21, 2023
2 parents c78e546 + d207854 commit 3be3d42
Show file tree
Hide file tree
Showing 22 changed files with 415 additions and 145 deletions.
9 changes: 9 additions & 0 deletions copilot-widget/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@
user: {
name: "John Doe",
},
containerProps: {
style: {
position: "fixed",
height: "100%",
bottom: "0",
right: "0",
width: "400px",
},
},
});
};
</script>
Expand Down
36 changes: 14 additions & 22 deletions copilot-widget/lib/CopilotWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import { useWidgetStateContext } from "./contexts/WidgetState";
import cn from "./utils/cn";
import ChatScreenWithSfxs from "./screens/ChatScreen";
import { IS_SERVER } from "./utils/is_server";
import root from 'react-shadow';
import css from '../styles/index.css?inline';

function useTrigger(selector: string, toggle: () => void) {
const trigger = useRef<HTMLElement | null>(
Expand All @@ -24,32 +22,26 @@ function useTrigger(selector: string, toggle: () => void) {

export function CopilotWidget({
triggerSelector,
className,
}: {
triggerSelector: string;
className?: string;
}) {
const [open, toggle] = useWidgetStateContext();
useTrigger(triggerSelector, toggle)
return (
<root.div
className={className}>
<div
id="opencopilot-aicopilot"
data-open={open}
className={cn(
"opencopilot-font-inter opencopilot-w-full opencopilot-overflow-hidden opencopilot-h-full sm:opencopilot-rounded-xl opencopilot-bg-white",
"opencopilot-opacity-0 opencopilot-transition-opacity opencopilot-ease",
open &&
"opencopilot-opacity-100 opencopilot-animate-in opencopilot-fade-in",
!open &&
"opencopilot-hidden opencopilot-animate-out opencopilot-fade-out"
)}
>
<ChatScreenWithSfxs />
</div>
<style>{css}</style>
</root.div>
<div
id="opencopilot-aicopilot"
data-open={open}
className={cn(
"opencopilot-font-inter opencopilot-w-full opencopilot-overflow-hidden opencopilot-h-full sm:opencopilot-rounded-xl opencopilot-bg-white opencopilot-shadow",
"opencopilot-opacity-0 opencopilot-transition-opacity opencopilot-ease",
open &&
"opencopilot-opacity-100 opencopilot-animate-in opencopilot-fade-in",
!open &&
"opencopilot-hidden opencopilot-animate-out opencopilot-fade-out"
)}
>
<ChatScreenWithSfxs />
</div>

);
}
15 changes: 13 additions & 2 deletions copilot-widget/lib/Root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,35 @@ import ConfigDataProvider, {
import WidgetState from "./contexts/WidgetState";
import { AxiosProvider } from "./contexts/axiosInstance";
import { InitialDataProvider } from "./contexts/InitialDataContext";
import root from 'react-shadow';
import css from '../styles/index.css?inline';

function Root({
children,
options,
containerProps,
}: {
children: React.ReactNode;
options: ConfigDataContextType;
containerProps?: React.DetailedHTMLProps<
React.HTMLAttributes<HTMLDivElement>,
HTMLDivElement
>;
}) {
const { style, id, ...containerProp } = containerProps || {}
return (
<React.Fragment>
<root.div {...containerProp} id="copilot-widget" style={{ width: '100%', height: '100%', ...style }}>
<ConfigDataProvider data={options}>
<WidgetState>
<AxiosProvider>
<InitialDataProvider>{children}</InitialDataProvider>
</AxiosProvider>
</WidgetState>
</ConfigDataProvider>
</React.Fragment>
<style>
{css}
</style>
</root.div>
);
}

Expand Down
4 changes: 4 additions & 0 deletions copilot-widget/lib/types/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ export type Options = {
triggerSelector: string;
apiUrl: string;
defaultOpen?: boolean;
containerProps?: React.DetailedHTMLProps<
React.HTMLAttributes<HTMLDivElement>,
HTMLDivElement
>;
user?: {
name?: string;
};
Expand Down
2 changes: 1 addition & 1 deletion copilot-widget/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@openchatai/copilot-widget",
"private": false,
"version": "1.6.1",
"version": "1.7.0",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down
3 changes: 2 additions & 1 deletion copilot-widget/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ declare global {
}
}

function initAiCoPilot({ triggerSelector, ...options }: Options) {
function initAiCoPilot({ triggerSelector, containerProps, ...options }: Options) {
const container = document.createElement("div") as HTMLDivElement;
container.id = "opencopilot-aicopilot";
document.body.appendChild(container);
Expand All @@ -18,6 +18,7 @@ function initAiCoPilot({ triggerSelector, ...options }: Options) {
options={{
...options,
}}
containerProps={containerProps}
>
<CopilotWidget triggerSelector={triggerSelector} />
</Root>
Expand Down
1 change: 0 additions & 1 deletion copilot-widget/vite.lib.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import tsconfigPaths from "vite-tsconfig-paths";

export default defineConfig({
plugins: [react(), dts({
outDir: './dist/',
entryRoot: './lib/',
strictOutput: true,
insertTypesEntry: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import React from 'react'
import { useAsyncFn } from 'react-use'
import { syncWorkflowById as $syncWorkflowById, getFlowById } from '@/data/new_flows'
import { toast } from '@/components/ui/use-toast';
import { useCopilot } from '../../../_context/CopilotProvider'
import useSWR from 'swr'
import { getActionsByBotId } from '@/data/actions'
import _, { uniqueId } from 'lodash'
import { useCopilot } from '@/app/(copilot)/copilot/_context/CopilotProvider'

type Props = {
children: React.ReactNode;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ import { zodResolver } from "@hookform/resolvers/zod";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import { createFlowByBotId } from "@/data/new_flows";
import { useCopilot } from "../../../_context/CopilotProvider";
import { useAsyncFn } from "react-use";
import { toast } from "@/components/ui/use-toast";
import { atom, useAtom } from "jotai";
import { useRouter } from "@/lib/router-events";
import { useCopilot } from "@/app/(copilot)/copilot/_context/CopilotProvider";

const formSchema = z.object({
name: z.string().min(2, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@ import React from 'react'
import { Button } from '@/components/ui/button'
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'
import { Link } from '@/lib/router-events'
import { useCopilot } from '../../../_context/CopilotProvider';
import useSWR, { mutate } from 'swr';
import { getFlowsByBotId } from '@/data/new_flows';
import { format } from 'timeago.js';
import _ from 'lodash';
import { EmptyBlock } from '@/components/domain/EmptyBlock';
import { useCopilot } from '@/app/(copilot)/copilot/_context/CopilotProvider';
export const revalidateWorkflows = (copilot_id: string) => mutate(copilot_id + '/workflows')

function WorkflowsTable() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export default function Widget({
},
}}
>
<CopilotWidget triggerSelector="#triggerSelector" className='max-w-sm min-w-full h-full max-h-screen' />
<CopilotWidget triggerSelector="#triggerSelector" />
</Root>
</ErrorBoundary>
}
1 change: 1 addition & 0 deletions dashboard/app/(copilot)/copilot/[copilot_id]/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export default function CopilotLayout({ children, params }: Props) {
<CopilotLayoutNavLink
href={copilotBase + "/workflow"}
IconComponent={Workflow}
segment="workflow"
label="Flows & Actions"
/>
<CopilotLayoutNavLink
Expand Down
2 changes: 1 addition & 1 deletion dashboard/app/(copilot)/copilot/[copilot_id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ export default function CopilotPage() {
<SelfHost />
</Accordion>
</div>
<div className="h-full w-fit p-4 shrink-0">
<div className="h-full w-fit p-4 max-w-sm xl:max-w-md">
<Widget token={CopilotToken} />
</div>
</div>
Expand Down
15 changes: 7 additions & 8 deletions dashboard/app/(main)/_parts/CopilotsContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";
import React from "react";
import { BotIcon, GalleryHorizontalEnd, Terminal } from "lucide-react";
import { GalleryHorizontalEnd } from "lucide-react";
import { Link } from "@/lib/router-events";
import useSwr from "swr";
import { CopilotType, listCopilots } from "@/data/copilot";
Expand All @@ -12,7 +12,6 @@ import { filterAtom } from "./Search";
import { useAtomValue } from "jotai";
import { Button } from "@/components/ui/button";
import { format } from "timeago.js";
import { Tooltip } from "@/components/domain/Tooltip";
import { motion, AnimatePresence } from 'framer-motion';

function customSort(list: CopilotType[], sortBy: Filter["sort"]) {
Expand Down Expand Up @@ -61,7 +60,7 @@ export function CopilotsContainer() {
)}
</EmptyBlock>
) : (
<div className="grid grid-cols-2 gap-6 md:grid-cols-3 auto-rows-fr py-4 lg:grid-cols-4">
<div className="grid gap-4 py-4 grid-cols-12">
{$copilots?.map((copilot, index) => {
const copilotUrl = "/copilot/" + copilot.id;
return (
Expand All @@ -79,12 +78,12 @@ export function CopilotsContainer() {
opacity: 0, y: 50,
filter: "blur(10px)"
}}
transition={{ duration: 0.2, delay: 0.01 * index }}
className="group"
transition={{ duration: 0.2, delay: 0.1 * index }}
className="group col-span-full lg:col-span-6 xl:col-span-3"
>
<div className="group relative flex h-56 items-center justify-center rounded-lg border-2 bg-accent group-hover:bg-secondary p-5 group-hover:shadow transition-shadow">
<div className="grid aspect-square h-20 shadow-lg place-content-center group-hover:scale-95 bg-primary transition-transform rounded-lg text-gray-100">
<GalleryHorizontalEnd className="h-12 w-12" />
<div className="group relative flex h-56 items-center justify-center rounded-lg border-2 bg-accent group-hover:bg-secondary transition-colors">
<div className="flex-center size-20 shadow-lg group-hover:scale-95 bg-primary transition-transform rounded-lg text-gray-100">
<GalleryHorizontalEnd className="size-12" />
</div>
</div>
<div className="mt-1.5 ps-1">
Expand Down
4 changes: 2 additions & 2 deletions dashboard/components/domain/new-flows-editor/ActionsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ function DropableAsideAction({ action, index }: { action: ActionResponseType, in
}
export const ASIDE_DROPABLE_ID = "BASE-ACTIONS";

export function ActionsList() {
export function ActionsList({ disabled }: { disabled?: boolean }) {
const { state: { actions } } = useController();

return (
Expand All @@ -88,7 +88,7 @@ export function ActionsList() {
No actions found <br /> you can create a new one from above or <br /> drag and drop a swagger file here. <br /> <br />
</div>

</EmptyBlock> : <Droppable droppableId={ASIDE_DROPABLE_ID} mode="standard">
</EmptyBlock> : <Droppable isDropDisabled={disabled} droppableId={ASIDE_DROPABLE_ID} mode="standard">
{
(provided) => {
return <div ref={provided.innerRef} {...provided.droppableProps} className='w-full shrink-0 divide-y flex overflow-y-hidden min-h-full flex-col items-start justify-start'>
Expand Down
6 changes: 3 additions & 3 deletions dashboard/components/domain/new-flows-editor/MagicAction.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react'
import {
AlertDialog, AlertDialogContent, AlertDialogDescription, AlertDialogTitle,
AlertDialog, AlertDialogContent, AlertDialogTitle,
AlertDialogCancel, AlertDialogFooter, AlertDialogHeader, AlertDialogTrigger
} from '@/components/ui/alert-dialog';
import { Button } from '@/components/ui/button';
Expand Down Expand Up @@ -55,7 +55,8 @@ export function MagicAction({ defaultValue }: { defaultValue?: string }) {
<AlertDialog open={open} onOpenChange={setOpen}>
<AlertDialogTrigger asChild>
<Button size='sm' variant='outline'>
<Sparkles></Sparkles> Build flow with AI (beta)
Build flow with AI (beta)
<Sparkles className='size-4 ms-1.5'/>
</Button>
</AlertDialogTrigger>
<AlertDialogContent asChild>
Expand All @@ -65,7 +66,6 @@ export function MagicAction({ defaultValue }: { defaultValue?: string }) {
<AlertDialogTitle>
Describe your flow
</AlertDialogTitle>

</AlertDialogHeader>
<FormField
control={form.control}
Expand Down
18 changes: 9 additions & 9 deletions dashboard/components/domain/new-flows-editor/Renderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ export function FlowRenderer() {
const onConnect: OnConnect = () => {
connectingNodeParams.current = null;
}

return (
<MemoizedDndContext nodes={nodes} actions={actions}>
<div className='flex items-center justify-between w-full h-full overflow-hidden'>
Expand All @@ -158,23 +158,23 @@ export function FlowRenderer() {
</Button>
</div>
<div className='flex-1 w-full overflow-auto'>
<ActionsList />
<ActionsList disabled={isBlocksEmpty} />
</div>
</aside>
<AddActionDrawer />
<div className='flex-1 relative h-full' ref={reactFlowWrapper}>
{
isBlocksEmpty && <div data-container='Empty block add button' className='absolute inset-0 z-50 flex-center bg-white p-4'>
<div className='flex items-center flex-col gap-4 '>
<p className='text-sm text-center font-medium'>
Start building your flow actions/steps:
isBlocksEmpty && <div data-container='Empty block add button' className='absolute inset-0 z-50 flex-center bg-secondary p-4'>
<div className='space-y-2'>
<p className='text-base text-center font-medium'>
Start building your flow actions/steps
</p>
<div className='px-4 space-x-2'>
<div className='px-4 flex items-center gap-3'>
<Button size='sm' onClick={() => insertEmptyBlockAfter()}>
<Plus></Plus>
I'll do it myself (recommended)
<Plus className='ms-1.5 size-4' />
</Button>
<span className='text-base font-semibold'>/or/</span>
<span className='text-base font-semibold'>/OR/</span>
<MagicAction defaultValue={description ?? ''} />
</div>
</div>
Expand Down
3 changes: 2 additions & 1 deletion dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
"react-use": "^17.4.0",
"react-use-wizard": "^2.2.3",
"reactflow": "^11.10.1",
"sharp": "^0.33.1",
"swr": "^2.2.4",
"tailwind-merge": "^1.14.0",
"tailwindcss-animate": "^1.0.7",
Expand All @@ -80,7 +81,7 @@
"prettier": "^3.0.3",
"prettier-plugin-tailwindcss": "^0.5.5",
"react-debounce-input": "^3.3.0",
"tailwindcss": "^3",
"tailwindcss": "^3.4.0",
"tailwindcss-debug-screens": "^2.2.1",
"typescript": "^5"
}
Expand Down
Loading

0 comments on commit 3be3d42

Please sign in to comment.