Skip to content

Commit

Permalink
feat(assistants): initial split screen builder (#60)
Browse files Browse the repository at this point in the history
Signed-off-by: Petr Kadlec <[email protected]>
  • Loading branch information
kapetr authored Nov 11, 2024
1 parent 8c37a0e commit c7ca18a
Show file tree
Hide file tree
Showing 81 changed files with 2,419 additions and 1,169 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"dependencies": {
"@ai-zen/node-fetch-event-source": "^2.1.4",
"@carbon/grid": "^11.22.0",
"@carbon/motion": "^11.17.0",
"@carbon/motion": "^11.22.0",
"@carbon/react": "^1.64.0",
"@carbon/styles": "^1.63.0",
"@dhmk/zustand-lens": "^5.0.0",
Expand Down
2 changes: 1 addition & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 8 additions & 5 deletions src/app/(main)/[projectId]/builder/[assistantId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ import { readAssistant } from '@/app/api/rsc';
import { decodeEntityWithMetadata } from '@/app/api/utils';
import { ErrorPage } from '@/components/ErrorPage/ErrorPage';
import { AssistantBuilderProvider } from '@/modules/assistants/builder/AssistantBuilderProvider';
import { Builder } from '@/modules/assistants/builder/Builder';
import { Assistant } from '@/modules/assistants/types';
import { LayoutInitializer } from '@/store/layout/LayouInitializer';
import { handleApiError } from '@/utils/handleApiError';
import { notFound } from 'next/navigation';

Expand All @@ -29,8 +31,7 @@ interface Props {
};
}

// TODO: use this page for split screen builder
export default async function EditAssistantPage({
export default async function AssistantBuilderPage({
params: { assistantId, projectId },
}: Props) {
let assistant;
Expand All @@ -55,8 +56,10 @@ export default async function EditAssistantPage({
}

return (
<AssistantBuilderProvider assistant={assistant}>
<></>
</AssistantBuilderProvider>
<LayoutInitializer layout={{ sidebarVisible: false }}>
<AssistantBuilderProvider assistant={assistant}>
<Builder />
</AssistantBuilderProvider>
</LayoutInitializer>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/**
* Copyright 2024 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import {
listMessagesWithFiles,
MESSAGES_PAGE_SIZE,
readAssistant,
readThread,
} from '@/app/api/rsc';
import { Thread } from '@/app/api/threads/types';
import { decodeEntityWithMetadata } from '@/app/api/utils';
import { ErrorPage } from '@/components/ErrorPage/ErrorPage';
import { AssistantBuilderProvider } from '@/modules/assistants/builder/AssistantBuilderProvider';
import { Builder } from '@/modules/assistants/builder/Builder';
import { Assistant } from '@/modules/assistants/types';
import { LayoutInitializer } from '@/store/layout/LayouInitializer';
import { handleApiError } from '@/utils/handleApiError';
import { notFound } from 'next/navigation';

interface Props {
params: {
assistantId: string;
projectId: string;
threadId: string;
};
}

export default async function AssistantBuilderPage({
params: { assistantId, projectId, threadId },
}: Props) {
let assistant;
let thread;

try {
const assistantResult = await readAssistant(projectId, assistantId);
if (!assistantResult) notFound();

assistant = decodeEntityWithMetadata<Assistant>(assistantResult);

const threadResult = await readThread(projectId, threadId);
if (!threadResult) notFound();

thread = decodeEntityWithMetadata<Thread>(threadResult);
} catch (e) {
const apiError = handleApiError(e);

if (apiError) {
return (
<ErrorPage
statusCode={apiError.error.code}
title={apiError.error.message}
/>
);
}
}

const initialMessages = await listMessagesWithFiles(projectId, threadId, {
limit: MESSAGES_PAGE_SIZE,
});

return (
<LayoutInitializer layout={{ sidebarVisible: false }}>
<AssistantBuilderProvider assistant={assistant}>
<Builder thread={thread} initialMessages={initialMessages} />
</AssistantBuilderProvider>
</LayoutInitializer>
);
}
29 changes: 29 additions & 0 deletions src/app/(main)/[projectId]/builder/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* Copyright 2024 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { AssistantBuilderProvider } from '@/modules/assistants/builder/AssistantBuilderProvider';
import { Builder } from '@/modules/assistants/builder/Builder';
import { LayoutInitializer } from '@/store/layout/LayouInitializer';

export default async function AssistantBuilderPage() {
return (
<LayoutInitializer layout={{ sidebarVisible: false }}>
<AssistantBuilderProvider>
<Builder />
</AssistantBuilderProvider>
</LayoutInitializer>
);
}
7 changes: 6 additions & 1 deletion src/app/(main)/[projectId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@
*/

import { AssistantsHome } from '@/modules/assistants/AssistantsHome';
import { LayoutInitializer } from '@/store/layout/LayouInitializer';

export default function HomePage() {
return <AssistantsHome />;
return (
<LayoutInitializer layout={{ sidebarVisible: true }}>
<AssistantsHome />
</LayoutInitializer>
);
}
2 changes: 2 additions & 0 deletions src/app/api/assistants/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,5 @@ export type AssistantsListQueryOrderBy =
FetchParamsOrderBy<AssistantsListQuery>;

export type AssistantModel = AssistantCreateBody['model'];

export type AssistantTool = AssistantResult['tools'][number];
37 changes: 37 additions & 0 deletions src/components/ClearButton/ClearButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* Copyright 2024 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { IconButton } from '@carbon/react';
import { Close } from '@carbon/react/icons';
import { ComponentProps } from 'react';

export function ClearButton({
className,
...props
}: Partial<ComponentProps<typeof IconButton>>) {
return (
<IconButton
kind="ghost"
wrapperClasses={className}
size="sm"
label="Clear"
autoAlign
{...props}
>
<Close />
</IconButton>
);
}
169 changes: 169 additions & 0 deletions src/components/DropdownSelector/DropdownSelector.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
/**
* Copyright 2024 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

@use 'styles/common' as *;

.root {
inline-size: 100%;
}

.field {
position: relative;
.clearButton {
position: absolute;
inset-block-start: rem(8px);
inset-inline-end: $spacing-04;
}
}
.openButton {
inline-size: 100%;
max-inline-size: none;
padding-block: 0;
align-items: center;
padding-inline-end: $spacing-10;
&:hover {
background-color: $background;
border-color: $background-inverse;
color: $text-primary;
}
&.isOpen {
> svg {
transform: rotate(-180deg);
}
}
&.isOpenDisabled {
padding-inline-end: $spacing-03;
> svg {
display: none;
}
}
}
.openButtonPlaceholder {
color: $text-placeholder;
}
.openButtonValue {
display: flex;
align-items: center;
justify-content: space-between;
inline-size: 100%;
}

.floating {
z-index: 1;
}

.listBox {
box-shadow: $box-shadow;
border-radius: $block-radius;
display: flex;
flex-direction: column;
background-color: $background;
&.multiple {
.list li > label :global(.#{$prefix}--checkbox-wrapper) {
display: flex;
}
.checkedIcon {
display: none;
}
}
}
.list {
padding: $spacing-05 $spacing-04;
overflow: auto;
max-block-size: 50vh;

h3 {
@include type-style('label-01');
color: $text-secondary;
padding-inline: $spacing-02;
}
ul {
display: flex;
flex-direction: column;
margin-block-start: $spacing-02;
li {
&[aria-selected='true'] {
> label {
background-color: $layer-hover-01;
.checkedIcon {
opacity: 1;
}
}
}
> label {
block-size: rem(48px);
display: flex;
align-items: center;
gap: $spacing-03;
padding-inline: $spacing-02 $spacing-03;
border-radius: $block-radius;

&:hover {
background-color: $layer-hover-01;
}

:global(.#{$prefix}--checkbox-wrapper) {
max-inline-size: rem(24px);
display: none;
}

.optionContent {
flex: 1 0 auto;
display: flex;
align-items: center;
font-size: rem(14px);
gap: $spacing-03;
}

.checkedIcon {
opacity: 0;
}
}
}
}
}

.actionBar {
border-block-start: 1px solid $border-subtle;
padding: $spacing-05 $spacing-05;
display: flex;
align-items: center;
justify-content: space-between;

> a {
font-size: rem(14px);
text-decoration: none;
}

.addSelectedButton {
padding-block: 0;
align-items: center;
display: flex;
gap: $spacing-02;
padding-inline-end: $spacing-06;
&:hover {
border-color: $text-primary;
background-color: $background;
color: $text-primary;
}
&:disabled {
border-color: $border-subtle;
:global(.#{$prefix}--tag) {
opacity: 0;
}
}
}
}
Loading

0 comments on commit c7ca18a

Please sign in to comment.