Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ const EditCourseForm: React.FC<EditCourseFormProps> = ({
<Form.Item
label="Coordinator Email"
name="coordinatorEmail"
tooltip="Email of the coordinator of the course"
tooltip="Email of the coordinator/instructor of the course"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i love these random flavor text changes in every PR

className="flex-1"
>
<Input allowClear={true} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,15 @@ interface FormValues {
content: string
source: string
pageNumber: string
name: string
}

interface ChatbotDocumentsProps {
interface ChatbotKnowledgeBaseProps {
params: Promise<{ cid: string }>
}

export default function ChatbotDocuments(
props: ChatbotDocumentsProps,
export default function ChatbotKnowledgeBase(
props: ChatbotKnowledgeBaseProps,
): ReactElement {
const params = use(props.params)
const courseId = Number(params.cid)
Expand All @@ -46,14 +47,15 @@ export default function ChatbotDocuments(
const [editRecordModalOpen, setEditRecordModalOpen] = useState(false)
const [form] = Form.useForm()
const [addDocChunkPopupVisible, setAddDocChunkPopupVisible] = useState(false)
const [dataLoading, setDataLoading] = useState(false)

const addDocument = async (values: FormValues) => {
const body: AddDocumentChunkParams = {
documentText: values.content,
metadata: {
name: 'Manually Inserted Information',
name: values.name || 'Manually Inserted Information',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm anticipating merge conflicts with my vector store refactor... sigh... that's what i get for having a PR that is old

type: 'inserted_document',
source: values.source ?? undefined,
source: values.source || undefined,
loc: values.pageNumber
? { pageNumber: parseInt(values.pageNumber) }
: undefined,
Expand Down Expand Up @@ -91,6 +93,7 @@ export default function ChatbotDocuments(

const fetchDocuments = useCallback(async () => {
if (courseId) {
setDataLoading(true)
await API.chatbot.staffOnly
.getAllDocumentChunks(courseId)
.then((response) => {
Expand All @@ -106,6 +109,7 @@ export default function ChatbotDocuments(
message.error('Failed to load documents: ' + errorMessage)
})
}
setDataLoading(false)
}, [courseId, setDocuments, setFilteredDocuments, search])

useEffect(() => {
Expand Down Expand Up @@ -270,25 +274,33 @@ export default function ChatbotDocuments(
>
<Input.TextArea />
</Form.Item>
<Form.Item
label="Name"
name="name"
tooltip={`When this chunk is cited, it will show this name. Defaults to "Manually Inserted Info" if not specified.`}
>
<Input placeholder="Manually Inserted Info" />
</Form.Item>
{/* <Form.Item label="Edited Chunk" name="editedChunk">
<Input.TextArea />
</Form.Item> */}
<Form.Item
label="Source"
label="Source URL"
name="source"
rules={[
{
type: 'url',
message: 'Please enter a valid URL',
},
]}
tooltip="When a student clicks on the citation, they will be redirected to this link"
tooltip="When a student clicks on the citation, they will be redirected to this link. Can be a link to anything."
>
<Input />
<Input placeholder="https://canvas.ubc.ca/courses/.../pages/..." />
</Form.Item>
<Form.Item
label="Page Number"
name="pageNumber"
tooltip="If the document in the Source URL is multi-page (e.g. a PDF), the content of the chunk should be found on this page. This is only for display purposes so that the citation says 'My doc p.3' for example. Feel free to leave this as 0 or blank."
rules={[
{
type: 'number',
Expand Down Expand Up @@ -335,6 +347,8 @@ export default function ChatbotDocuments(
dataSource={filteredDocuments}
size="small"
className="w-full"
bordered
loading={documents.length === 0 && dataLoading}
locale={{
emptyText: (
<Empty
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ const EditChatbotQuestionModal: React.FC<EditChatbotQuestionModalProps> = ({
const newChunk: AddDocumentChunkParams = {
documentText: values.question + '\nAnswer:' + values.answer,
metadata: {
name: 'inserted Q&A',
name: 'Previously Asked Question',
type: 'inserted_question',
id: editingRecord.vectorStoreId,
courseId: cid,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ export default function AddCoursePage(): ReactElement {
<Form.Item
label="Coordinator Email"
name="coordinatorEmail"
tooltip="Email of the coordinator of the course"
tooltip="Email of the coordinator/instructor of the course"
>
<Input allowClear={true} />
</Form.Item>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import UserAccessTokens from './UserAccessTokens'
import ClearProfileCache from './ClearProfileCache'

const AdvancedSettings: React.FC = () => {
return (
<div className="flex w-full flex-col gap-2">
<h2 className="text-2xl font-bold">Advanced Settings</h2>
<UserAccessTokens />
<ClearProfileCache />
</div>
)
}

export default AdvancedSettings
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

THANK. YOU.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it might be abusable though depending on your route

Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { API } from '@/app/api'
import { useUserInfo } from '@/app/contexts/userContext'
import { getErrorMessage } from '@/app/utils/generalUtils'
import { DeleteOutlined, QuestionCircleOutlined } from '@ant-design/icons'
import { Button, Card, message, Tooltip } from 'antd'
import { useState } from 'react'

const ClearProfileCache: React.FC = () => {
const { userInfo, setUserInfo } = useUserInfo()
const [isLoading, setIsLoading] = useState(false)

return (
<>
{userInfo && (
<Card title={<h3> Profile Cache</h3>} classNames={{ body: 'py-2' }}>
<Tooltip
title={`Notice some weird behavior where the server is giving you errors but the client looks fine on your end? The profile caching may have become unsynced. Click this button to clear the cache (there are no consequences of doing so).`}
>
Clear Backend Profile Cache
<QuestionCircleOutlined className="ml-0.5 text-gray-500" />
</Tooltip>
<Button
icon={<DeleteOutlined />}
loading={isLoading}
onClick={async () => {
setIsLoading(true)
await API.profile
.clearCache()
.then(async () => {
await API.profile
.getUser()
.then((userDetails) => {
setUserInfo(userDetails)
message.success(
'Profile cache cleared successfully. You may want to refresh your page.',
)
})
.catch((error) => {
message.error(
'Cache cleared but error getting new user details: ' +
getErrorMessage(error),
)
})
})
.catch((error) => {
message.error(
'Error clearing profile cache: ' + getErrorMessage(error),
)
})
setIsLoading(false)
}}
className="ml-2"
>
Clear
</Button>
</Card>
)}
</>
)
}

export default ClearProfileCache
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { getErrorMessage } from '@/app/utils/generalUtils'
import { ExclamationCircleOutlined } from '@ant-design/icons'
import { UserCourse } from '@koh/common'
import { Button, message, Modal, Table, TableColumnsType } from 'antd'
import useSWR from 'swr'

const { confirm } = Modal

Expand Down Expand Up @@ -56,7 +55,11 @@ const CoursePreference: React.FC = () => {
const InstructorCell = ({ courseId }: { courseId: number }) => {
const course = useCourse(courseId)

return <>{course.course?.coordinator_email}</>
return (
<div className="max-w-[5.45rem] overflow-x-scroll whitespace-nowrap md:max-w-full md:overflow-x-auto">
{course.course?.coordinator_email}
</div>
)
}

const columns: TableColumnsType = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import CoursePreference from './CoursePreference'
import EmailNotifications from './EmailNotifications'
import UserChatbotHistory from './UserChatbotHistory'
import { useSearchParams } from 'next/navigation'
import UserAccessTokens from '@/app/(dashboard)/profile/components/UserAccessTokens'
import AdvancedSettings from './AdvancedSettings'

const ProfileSettings: React.FC = () => {
const params = useSearchParams()
Expand All @@ -24,8 +24,8 @@ const ProfileSettings: React.FC = () => {
return SettingsOptions.PREFERENCES
case 'chatbot_history':
return SettingsOptions.CHATBOT_HISTORY
case 'access_tokens':
return SettingsOptions.ACCESS_TOKENS
case 'advanced':
return SettingsOptions.ADVANCED
default:
return SettingsOptions.PROFILE
}
Expand Down Expand Up @@ -60,12 +60,10 @@ const ProfileSettings: React.FC = () => {
{currentSettings === SettingsOptions.PREFERENCES && (
<CoursePreference />
)}
{currentSettings === SettingsOptions.ACCESS_TOKENS && (
<UserAccessTokens />
)}
{currentSettings === SettingsOptions.CHATBOT_HISTORY && (
<UserChatbotHistory />
)}
{currentSettings === SettingsOptions.ADVANCED && <AdvancedSettings />}
</Col>
</Space>
</Row>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import CoursePreference from './CoursePreference'
import { useMediaQuery } from '@/app/hooks/useMediaQuery'
import EmailNotifications from './EmailNotifications'
import UserChatbotHistory from './UserChatbotHistory'
import AdvancedSettings from './AdvancedSettings'

interface SettingsMenuProps {
currentSettings: SettingsOptions
Expand Down Expand Up @@ -59,6 +60,11 @@ const SettingsMenu: React.FC<SettingsMenuProps> = ({
label: 'Chatbot History',
children: <UserChatbotHistory />,
},
{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i thought having it as a family of options might've been useful, the dropdown also prevented it from being shown by default (comparable to other advanced settings in similar webapps)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's about the same UX either way (plus it's a rare usecase), but I could change it back if you'd prefer. Also I'm not entirely sure I know what you mean by the dropdown preventing it from being shown by default?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC, the advanced options would only show when highlighted or selected. ants is weird tho and i cant remember exactly

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah I believe before it was a submenu, where you click Advanced -> submenu with [Access Tokens, Clear Cache] -> Click on item and taken to dedicated page for that item.

What I did here was just make one "Advanced" page with both Access Tokens and Clear Cache on the same page, which I guess is shown on the screenshots in the PR description. It's basically the same, maybe just a little more consistent with our profile settings pages but it's kinda subjective.

key: SettingsOptions.ADVANCED,
label: 'Advanced',
children: <AdvancedSettings />,
},
]}
/>
) : (
Expand Down Expand Up @@ -88,16 +94,9 @@ const SettingsMenu: React.FC<SettingsMenuProps> = ({
icon: <HistoryOutlined />,
},
{
key: 'Advanced',
key: SettingsOptions.ADVANCED,
label: 'Advanced',
icon: <SettingOutlined />,
children: [
{
key: SettingsOptions.ACCESS_TOKENS,
label: 'Access Tokens',
icon: <KeyOutlined />,
},
],
},
]}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const UserAccessTokens: React.FC = () => {
<div className={'flex flex-col gap-12'}>
<Card
title="Learning Management System Access Tokens"
classNames={{ body: 'flex flex-col gap-4' }}
classNames={{ body: 'flex flex-col gap-4', title: 'text-wrap' }}
>
<p>
These are access tokens generated for learning management systems your
Expand Down
8 changes: 5 additions & 3 deletions packages/frontend/app/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,8 @@ export class APIClient {
this.req('DELETE', `/api/v1/profile/delete_profile_picture`),
readChangelog: async (): Promise<void> =>
this.req('PATCH', `/api/v1/profile/read_changelog`, undefined),
clearCache: async (): Promise<void> =>
this.req('DELETE', `/api/v1/profile/clear_cache`),
}

chatbot = {
Expand Down Expand Up @@ -720,19 +722,19 @@ export class APIClient {
includeQueueQuestions: boolean = true,
includeAnytimeQuestions: boolean = true,
includeChatbotInteractions: boolean = true,
groupBy: 'day' | 'week' = 'week'
groupBy: 'day' | 'week' = 'week',
): Promise<ToolUsageExportData[]> => {
const queryParams = new URLSearchParams({
includeQueueQuestions: includeQueueQuestions.toString(),
includeAnytimeQuestions: includeAnytimeQuestions.toString(),
includeChatbotInteractions: includeChatbotInteractions.toString(),
groupBy
groupBy,
})

return this.req(
'GET',
`/api/v1/courses/${courseId}/export-tool-usage?${queryParams.toString()}`,
undefined
undefined,
)
},
}
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/app/typings/enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ export enum SettingsOptions {
TEAMS_SETTINGS = 'TEAMS_SETTINGS',
PREFERENCES = 'PREFERENCES',
CHATBOT_HISTORY = 'CHATBOT_HISTORY',
ACCESS_TOKENS = 'ACCESS_TOKENS',
ADVANCED = 'ADVANCED',
}
2 changes: 1 addition & 1 deletion packages/server/src/asyncQuestion/asyncQuestion.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export class AsyncQuestionService {
content: `<br> <b>${commenterIsStaff ? commenter.name : 'Someone'} has commented on your "${question.questionAbstract ?? (question.questionText ? question.questionText.slice(0, 50) : '')}" Anytime Question:</b>
<br> <b>Comment Text<b>: ${comment.commentText}
<br>
<br> Note: Do NOT reply to this email. <a href="${process.env.DOMAIN}/course/${question.courseId}/async_centre">View and Reply Here</a> <br>`,
<br> Do NOT reply to this email. <a href="${process.env.DOMAIN}/course/${question.courseId}/async_centre"><b>View and Answer It Here</b></a> <br>`,
})
.catch((err) => {
console.error(
Expand Down
Loading