Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ui): 669-annotations #908

Merged
merged 38 commits into from
Aug 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
ca19c1f
init
andrewrisse Aug 6, 2024
6e9be0f
Fix rag e2e
andrewrisse Aug 7, 2024
539c15f
move e2e setup steps to after authentication
andrewrisse Aug 7, 2024
5215de4
Merge branch '856-type-issues' into 669-annotations
andrewrisse Aug 7, 2024
1273649
init
andrewrisse Aug 7, 2024
0495d18
wip
andrewrisse Aug 7, 2024
061820d
working with btns
andrewrisse Aug 7, 2024
f30bcba
wip, see todos
andrewrisse Aug 7, 2024
bb0db0e
openai feature flag
andrewrisse Aug 8, 2024
2b24341
openai feature flag 2
andrewrisse Aug 8, 2024
830ce8d
add tests, need to fix dockerfile
andrewrisse Aug 8, 2024
bf18d9c
add libreoffice to dockerfile
andrewrisse Aug 9, 2024
cd82378
update dockerfile 1
andrewrisse Aug 9, 2024
abb52ae
update dockerfile 2
andrewrisse Aug 9, 2024
cb8e8c8
update dockerfile 3
andrewrisse Aug 9, 2024
9492b72
update dockerfile 4
andrewrisse Aug 9, 2024
47be881
update dockerfile 5
andrewrisse Aug 9, 2024
0a7b09b
update dockerfile 6
andrewrisse Aug 9, 2024
3a9b26d
add todo
andrewrisse Aug 9, 2024
e5ecb0a
try add convert option
andrewrisse Aug 13, 2024
af936b2
Add zoom
andrewrisse Aug 13, 2024
bc00ce5
enable toolbar for debug
andrewrisse Aug 13, 2024
baab6f6
Add fonts to dockerfile
andrewrisse Aug 13, 2024
886cc02
add comment
andrewrisse Aug 13, 2024
4565423
Merge branch 'main' into 669-annotations
andrewrisse Aug 13, 2024
39efe34
update csp and fix loading indicator pulse
andrewrisse Aug 13, 2024
61fd2f0
merge main
andrewrisse Aug 13, 2024
cb256fd
format
andrewrisse Aug 13, 2024
c1a3a21
add mime type
andrewrisse Aug 13, 2024
4f23ac1
add test for csv
andrewrisse Aug 13, 2024
67b5dd8
fix unit test
andrewrisse Aug 13, 2024
418183f
move navigator mock to setup
andrewrisse Aug 13, 2024
f675482
try to fix workflow
andrewrisse Aug 13, 2024
103d38e
try to fix workflow 2
andrewrisse Aug 14, 2024
6e68518
Merge branch 'main' into 669-annotations
andrewrisse Aug 14, 2024
093a36d
merge main and remove unecessary comment
andrewrisse Aug 14, 2024
82f0eb0
re-install missing dev dep
andrewrisse Aug 14, 2024
75ccf7e
Remove cleanup step from test setup
andrewrisse Aug 14, 2024
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
23 changes: 15 additions & 8 deletions src/leapfrogai_ui/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
FROM node:18-alpine AS builder
RUN apk update && apk upgrade && apk add --no-cache libreoffice openjdk11-jre

# Add fonts for converting docs to pdfs
RUN apk add --no-cache \
fontconfig \
msttcorefonts-installer \
&& update-ms-fonts \
&& fc-cache -f

ENV JAVA_HOME=/usr/lib/jvm/java-11-openjdk
ENV PATH=${JAVA_HOME}/bin:$PATH

WORKDIR /app
COPY package.json ./
COPY package-lock.json ./
Expand All @@ -8,16 +20,11 @@ ENV NODE_ENV=production
RUN npm run build
RUN npm prune

FROM cgr.dev/chainguard/node:latest

WORKDIR /app
COPY --chown=node:node --from=builder /app/build build/
COPY --chown=node:node --from=builder /app/node_modules node_modules/
COPY --chown=node:node package.json .
EXPOSE 3000
ENV NODE_ENV=production
# Disable request size limit
ENV BODY_SIZE_LIMIT=Infinity
ENV PROTOCOL_HEADER=x-forwarded-proto
ENV HOST_HEADER=x-forwarded-host
CMD ["build"]
EXPOSE 3000

CMD ["build"]
26 changes: 26 additions & 0 deletions src/leapfrogai_ui/package-lock.json

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

1 change: 1 addition & 0 deletions src/leapfrogai_ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
"fuse.js": "^7.0.0",
"highlight.js": "^11.10.0",
"isomorphic-dompurify": "^2.13.0",
"libreoffice-convert": "^1.6.0",
"lit": "^3.1.4",
"markdown-it": "^14.1.0",
"openai": "^4.52.7",
Expand Down
1 change: 1 addition & 0 deletions src/leapfrogai_ui/src/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
display: flex;
flex-grow: 1;
flex-direction: column;
max-width: calc(100% - 255px);
overflow: auto;
padding-top: 2rem;
height: calc(100vh - var(--header-height));
Expand Down
1 change: 1 addition & 0 deletions src/leapfrogai_ui/src/app.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ declare global {
safeGetSession: () => Promise<{ session: Session | null; user: User | null }>;
session: Session | null;
user: User | null;
isUsingOpenAI: boolean;
}
interface PageData {
session: Session | null;
Expand Down
2 changes: 2 additions & 0 deletions src/leapfrogai_ui/src/hooks.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { createServerClient } from '@supabase/ssr';
import { type Handle, redirect } from '@sveltejs/kit';
import { sequence } from '@sveltejs/kit/hooks';
import { env } from '$env/dynamic/public';
import { env as envPrivate } from '$env/dynamic/private';

const supabase: Handle = async ({ event, resolve }) => {
/**
Expand Down Expand Up @@ -69,6 +70,7 @@ const authGuard: Handle = async ({ event, resolve }) => {
const { session, user } = await event.locals.safeGetSession();
event.locals.session = session;
event.locals.user = user;
event.locals.isUsingOpenAI = !!envPrivate.OPENAI_API_KEY;

// protect all routes under /chat
if (!event.locals.session && event.url.pathname.startsWith('/chat')) {
Expand Down
140 changes: 140 additions & 0 deletions src/leapfrogai_ui/src/lib/components/Citatation.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import { getFakeFiles } from '$testUtils/fakeData';
import {
mockConvertFile,
mockConvertFileError,
mockGetFile,
mockGetFileError
} from '$lib/mocks/file-mocks';
import Citation from '$components/Citation.svelte';
import { render, screen } from '@testing-library/svelte';
import { afterAll, beforeEach, vi } from 'vitest';
import userEvent from '@testing-library/user-event';
import { toastStore, uiStore } from '$stores';
import {
CONVERT_FILE_ERROR_MSG_TOAST,
FILE_DOWNLOAD_ERROR_MSG_TOAST,
OPENAI_DOWNLOAD_DISABLED_MSG_TOAST
} from '$constants/toastMessages';

vi.mock('$app/environment', () => ({
browser: true
}));

vi.stubGlobal('window', {
...window,
open: vi.fn(),
URL: {
...window.URL,
createObjectURL: vi.fn(() => 'blob:http://localhost/file'),
revokeObjectURL: vi.fn()
},
navigator: {
clipboard: {
writeText: vi.fn()
}
}
});

describe('Citation', () => {
const toastSpy = vi.spyOn(toastStore, 'addToast');

beforeEach(() => {
uiStore.set({
openSidebar: true,
isUsingOpenAI: false
});
});

afterAll(() => {
vi.restoreAllMocks();
vi.unstubAllGlobals();
});

it('renders an iframe when a pdf is clicked', async () => {
const file = getFakeFiles({ numFiles: 1 })[0];
mockGetFile(file.id, 'test');

render(Citation, { file, index: 1 });

await userEvent.click(screen.getByTestId(`${file.id}-citation-btn`));
await screen.findByTitle(`${file.id}-iframe`);
});

it('renders an iframe when a non-pdf file type is clicked (converted to pdf)', async () => {
const file = getFakeFiles({ numFiles: 1 })[0];
mockGetFile(file.id, 'test', 'text/plain');
mockConvertFile('fake content');

render(Citation, { file, index: 1 });

await userEvent.click(screen.getByTestId(`${file.id}-citation-btn`));
await screen.findByTitle(`${file.id}-iframe`);
});

it('shows a toast and does not render an iframe when OpenAI is being used', async () => {
const file = getFakeFiles({ numFiles: 1 })[0];
mockGetFile(file.id, 'test');
uiStore.set({
openSidebar: true,
isUsingOpenAI: true
});
render(Citation, { file, index: 1 });

await userEvent.click(screen.getByTestId(`${file.id}-citation-btn`));
expect(screen.queryByTitle(`${file.id}-iframe`)).not.toBeInTheDocument();
expect(toastSpy).toHaveBeenCalledWith({
...OPENAI_DOWNLOAD_DISABLED_MSG_TOAST
});
});
it('displays a toast when an error occurs after clicking a citation', async () => {
const file = getFakeFiles({ numFiles: 1 })[0];
mockGetFileError(file.id);

render(Citation, { file, index: 1 });
await userEvent.click(screen.getByTestId(`${file.id}-citation-btn`));

expect(toastSpy).toHaveBeenCalledWith({
...FILE_DOWNLOAD_ERROR_MSG_TOAST
});
});

it('displays a toast when an error occurs when converting a file to pdf', async () => {
const file = getFakeFiles({ numFiles: 1 })[0];
mockGetFile(file.id, 'test', 'text/plain');
mockConvertFileError();

render(Citation, { file, index: 1 });
await userEvent.click(screen.getByTestId(`${file.id}-citation-btn`));

expect(toastSpy).toHaveBeenCalledWith({
...FILE_DOWNLOAD_ERROR_MSG_TOAST
});
});
it('displays a toast when the file type is not supported for download', async () => {
const file = getFakeFiles({ numFiles: 1 })[0];
mockGetFile(file.id, 'test', 'fakeFileType');

render(Citation, { file, index: 1 });
await userEvent.click(screen.getByTestId(`${file.id}-citation-btn`));

expect(toastSpy).toHaveBeenCalledWith({
...CONVERT_FILE_ERROR_MSG_TOAST
});
});
it('open a new tab when the open in new tab button is clicked', async () => {
const windowOpenSpy = vi.spyOn(window, 'open');
const file = getFakeFiles({ numFiles: 1 })[0];

mockGetFile(file.id, 'test');

render(Citation, { file, index: 1 });

await userEvent.click(screen.getByTestId(`${file.id}-citation-btn`));
await screen.findByTitle(`${file.id}-iframe`);
await userEvent.click(screen.getByTestId(`file-${file.id}-open-new-tab-btn`));
expect(windowOpenSpy).toHaveBeenCalledTimes(1);
expect(windowOpenSpy).toHaveBeenCalledWith('blob:http://localhost/file', '_blank');
});

// Note - downloading of file tested via E2E
});
Loading