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: workspaces #1156

Merged
merged 95 commits into from
Dec 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
55dd355
feat: doctypes for workspaces
nikkothari22 Oct 22, 2024
111bb67
perf: cache channel members
nikkothari22 Nov 8, 2024
2a22cb5
perf: use cache for channel membership
nikkothari22 Nov 8, 2024
d2bdf60
perf: use cache for peer user ID
nikkothari22 Nov 8, 2024
d50df57
perf: do not invalidate channel cache on message send
nikkothari22 Nov 8, 2024
ba64b5d
Merge branch 'develop' into raven-orgs
nikkothari22 Nov 12, 2024
0803df7
Merge branch 'develop' into raven-orgs
nikkothari22 Nov 14, 2024
6f1cb12
fix: ignore user permissions when adding system messages
nikkothari22 Nov 16, 2024
60485ff
fix: channel members cache
nikkothari22 Nov 16, 2024
dec775a
fix: delete reactions when channel is deleted #1151
nikkothari22 Nov 16, 2024
9330ee5
Merge branch 'develop' into raven-orgs
nikkothari22 Nov 16, 2024
3c57906
Merge branch 'develop' into raven-orgs
nikkothari22 Nov 17, 2024
7cfc9ac
wip(ui): workspaces sidebar
nikkothari22 Nov 17, 2024
732fa7e
chore: add is_dm_thread for threads in DM channels
nikkothari22 Nov 17, 2024
bc6acd5
chore: patches for workspaces
nikkothari22 Nov 17, 2024
8f6edc3
fix:(tests): chat stream test with workspaces
nikkothari22 Nov 17, 2024
8c2f040
chore: linting
nikkothari22 Nov 17, 2024
9e27bed
chore(linting): convert SQL query to query builder
nikkothari22 Nov 17, 2024
85fe554
fix: do not auto-assign workspace to channel if DM thread
nikkothari22 Nov 17, 2024
13a2ffc
fix(tests): do not create channel member for chat stream test
nikkothari22 Nov 17, 2024
72899d8
fix: mutate members when creating a channel
nikkothari22 Nov 22, 2024
3d5a19e
fix: link preview spacing and height
nikkothari22 Nov 22, 2024
0f60418
chore: remove unused imports
nikkothari22 Nov 22, 2024
c47e302
perf: installed millionjs
nikkothari22 Nov 22, 2024
bab1226
perf: memoize DateTooltip
nikkothari22 Nov 22, 2024
2e73226
perf: reduce rerenders in ChatBoxBody
nikkothari22 Nov 22, 2024
27ceaff
Merge pull request #1162 from The-Commit-Company/fix-perf
nikkothari22 Nov 22, 2024
858424b
Merge branch 'develop' into raven-orgs
nikkothari22 Nov 22, 2024
76a3802
fix: remove MillionLint
nikkothari22 Nov 26, 2024
5640c6b
chore: update packages
nikkothari22 Nov 26, 2024
d5597e2
Merge branch 'develop' into raven-orgs
nikkothari22 Nov 27, 2024
cb78648
fix: delete thread channel if message is deleted
nikkothari22 Nov 29, 2024
09daa80
fix: do not allow non-admins to change channel name and description
nikkothari22 Nov 29, 2024
c4d56e0
chore: remove unused variable
nikkothari22 Nov 29, 2024
3565119
feat: updated permission checks with tests
nikkothari22 Nov 29, 2024
0791204
fix: revert yarn.lock
nikkothari22 Nov 29, 2024
3eb38b9
Merge branch 'develop' into raven-orgs
nikkothari22 Nov 29, 2024
0666d34
chore: linting
nikkothari22 Nov 29, 2024
0a6c7e2
feat: fetch workspaces for user
nikkothari22 Nov 29, 2024
c4e5d78
fix: perm check for joining threads
nikkothari22 Dec 6, 2024
a7e9fb9
fix: poll vote perm check
nikkothari22 Dec 6, 2024
3ae3f6c
fix: login page error banner
nikkothari22 Dec 6, 2024
98efebc
feat: add toggle theme in command menu
nikkothari22 Dec 6, 2024
2d836e4
fix: do not retry doctype preview on error
nikkothari22 Dec 6, 2024
40a6b4a
feat: show workspace name in command menu
nikkothari22 Dec 6, 2024
ca81367
feat: only fetch channels if user is part of workspace
nikkothari22 Dec 6, 2024
615bc2b
feat: show workspace in forward message
nikkothari22 Dec 6, 2024
9d83393
feat: show workspace in channel dropdown
nikkothari22 Dec 6, 2024
28c3afd
fix: always show create channel button
nikkothari22 Dec 6, 2024
bc0d826
chore: update packages
nikkothari22 Dec 6, 2024
341b6e8
fix: use random hash for DM channel IDs
nikkothari22 Dec 6, 2024
3f4f16b
fix: fetch DM channels
nikkothari22 Dec 6, 2024
ea9b543
fix: perm check for thread DMs
nikkothari22 Dec 6, 2024
3d4b18f
fix(test): removed unneccessary assertion
nikkothari22 Dec 6, 2024
e8ce5cf
fix: poll creation API type
nikkothari22 Dec 6, 2024
e9ef0f9
feat: workspace switcher
nikkothari22 Dec 6, 2024
f993a66
fix: users can only mention channels in the given workspace
nikkothari22 Dec 6, 2024
2af77a0
feat: thread and saved messages respect workspace
nikkothari22 Dec 6, 2024
531bfca
feat: join workspaces from switcher
nikkothari22 Dec 6, 2024
cec204e
chore: make a default workspace on install
nikkothari22 Dec 6, 2024
65d0a4b
fix: do not reroute if only one workspace
nikkothari22 Dec 6, 2024
a0287fe
fix: route using effect
nikkothari22 Dec 6, 2024
b938048
fix: do not route if only one workspace
nikkothari22 Dec 6, 2024
fb3cab0
fix: "try" adding all users to default workspace on install
nikkothari22 Dec 6, 2024
4ae8a05
feat: show unread counts on workspaces
nikkothari22 Dec 6, 2024
2f80f9a
fix: only fetch unread counts for members
nikkothari22 Dec 6, 2024
2d67382
fix: show workspace switcher grid on index
nikkothari22 Dec 6, 2024
361d1d7
fix: update user cache when updating status and image
nikkothari22 Dec 6, 2024
274c449
fix(FrappeHR): map companies to workspaces in Raven
nikkothari22 Dec 6, 2024
e42c4c2
fix: translate error message
nikkothari22 Dec 6, 2024
115f90c
fix: remove flicker on dialog closing - downgraded Radix to 3.1.4
nikkothari22 Dec 7, 2024
b546255
fix: HR integration with department channels
nikkothari22 Dec 7, 2024
f0278bd
fix: error page routing
nikkothari22 Dec 7, 2024
ddf72cd
revert: upgrade radix themes because of dep mismatch between vaul and…
nikkothari22 Dec 7, 2024
d75b524
fix: force RadixUI dialog to v1.1.1
nikkothari22 Dec 7, 2024
5ce5f0a
feat: add workspace flow
nikkothari22 Dec 7, 2024
9338190
fix: move settings page
nikkothari22 Dec 7, 2024
75ec1bb
fix: settings page routing
nikkothari22 Dec 7, 2024
63a16f0
fix: route to last workspace and channel automatically on load
nikkothari22 Dec 7, 2024
6047350
fix: do not refetch on error
nikkothari22 Dec 7, 2024
2dbe719
feat: allow Raven Admins to configure settings
nikkothari22 Dec 7, 2024
d749b7a
fix: disable forms if no perms
nikkothari22 Dec 7, 2024
1057b94
feat: empty states for all configuration pages
nikkothari22 Dec 7, 2024
aa200b3
fix: fix settings sidebar
nikkothari22 Dec 7, 2024
916c468
fix: non-workspace-admins cannot create channels
nikkothari22 Dec 7, 2024
eeb1057
fix: limit workspace description to two lines
nikkothari22 Dec 13, 2024
0b55104
fi(ui): setting page UI on mobile
nikkothari22 Dec 13, 2024
cd26552
feat: join and leave workspace flows
nikkothari22 Dec 13, 2024
adad90b
feat: add workspace from list
nikkothari22 Dec 13, 2024
c8ce4fc
feat: workspace member removal and admin management
nikkothari22 Dec 13, 2024
3e22766
fix(ui): loader color
nikkothari22 Dec 14, 2024
45d07d3
feat: workspace member manager
nikkothari22 Dec 14, 2024
0cf9c6b
feat: add members to workspace
nikkothari22 Dec 14, 2024
44fae19
feat: workspace image uploader
nikkothari22 Dec 14, 2024
6a7ffda
fix: only allow search for channels where the user is a member
nikkothari22 Dec 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
3 changes: 3 additions & 0 deletions frontend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,6 @@ dist-ssr
*.njsproj
*.sln
*.sw?

# Million Lint
.million
20 changes: 12 additions & 8 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"copy-html-entry": "cp ../raven/public/raven/index.html ../raven/www/raven.html"
},
"dependencies": {
"@radix-ui/themes": "^3.1.3",
"@radix-ui/themes": "3.1.4",
"@tiptap/extension-code-block-lowlight": "2.5.9",
"@tiptap/extension-highlight": "2.5.9",
"@tiptap/extension-image": "2.5.9",
Expand All @@ -33,35 +33,36 @@
"cal-sans": "^1.0.1",
"chrono-node": "^2.7.7",
"clsx": "^2.1.0",
"cmdk": "^1.0.0",
"cmdk": "^1.0.4",
"cva": "npm:class-variance-authority",
"dayjs": "^1.11.11",
"downshift": "^8.3.1",
"emoji-picker-element": "^1.22.3",
"emoji-picker-element": "^1.25.0",
"firebase": "^10.9.0",
"frappe-react-sdk": "^1.8.0",
"frappe-react-sdk": "^1.9.0",
"highlight.js": "^11.9.0",
"html-react-parser": "^5.1.8",
"jotai": "^2.9.3",
"jotai": "^2.10.3",
"js-cookie": "^3.0.5",
"lowlight": "^3.1.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-dropzone": "^14.2.3",
"react-error-boundary": "^4.0.13",
"react-hook-form": "^7.52.2",
"react-icons": "^5.3.0",
"react-icons": "^5.4.0",
"react-idle-timer": "^5.7.2",
"react-intersection-observer": "^9.10.3",
"react-router-dom": "^6.26.1",
"react-virtuoso": "^4.12.3",
"react-zoom-pan-pinch": "^3.4.4",
"sonner": "^1.5.0",
"sonner": "^1.7.0",
"tailwindcss": "^3.4.10",
"tailwindcss-animate": "^1.0.7",
"tippy.js": "^6.3.7",
"turndown": "^7.2.0",
"use-double-tap": "^1.3.6",
"vaul": "^0.9.1",
"vaul": "^1.1.1",
"vite": "^4.5.5",
"vite-plugin-pwa": "^0.20.0",
"vite-plugin-svgr": "^4.2.0"
Expand All @@ -72,5 +73,8 @@
"@types/react-dom": "^18.2.19",
"@types/turndown": "^5.0.4",
"typescript": "^5.3.3"
},
"resolutions": {
"@radix-ui/react-dialog": "1.1.1"
}
}
128 changes: 71 additions & 57 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import { FrappeProvider } from 'frappe-react-sdk'
import { Route, RouterProvider, createBrowserRouter, createRoutesFromElements } from 'react-router-dom'
import { Navigate, Route, RouterProvider, createBrowserRouter, createRoutesFromElements } from 'react-router-dom'
import { MainPage } from './pages/MainPage'
import { ProtectedRoute } from './utils/auth/ProtectedRoute'
import { UserProvider } from './utils/auth/UserProvider'
import { ChannelRedirect } from './utils/channel/ChannelRedirect'
import "cal-sans";
import { ThemeProvider } from './ThemeProvider'
import { Toaster } from 'sonner'
import { useStickyState } from './hooks/useStickyState'
import MobileTabsPage from './pages/MobileTabsPage'
import Cookies from 'js-cookie'
import ErrorPage from './pages/ErrorPage'
import WorkspaceSwitcher from './pages/WorkspaceSwitcher'
import WorkspaceSwitcherGrid from './components/layout/WorkspaceSwitcherGrid'

/** Following keys will not be cached in app cache */
const NO_CACHE_KEYS = [
Expand All @@ -19,9 +20,13 @@ const NO_CACHE_KEYS = [
"frappe.model.workflow.get_transitions",
"frappe.desk.reportview.get_count",
"frappe.core.doctype.server_script.server_script.enabled",
"raven.api.message_actions.get_action_defaults"
"raven.api.message_actions.get_action_defaults",
"raven.api.document_link.get_preview_data"
]

const lastWorkspace = localStorage.getItem('ravenLastWorkspace') ?? ''
const lastChannel = localStorage.getItem('ravenLastChannel') ?? ''


const router = createBrowserRouter(
createRoutesFromElements(
Expand All @@ -31,64 +36,73 @@ const router = createBrowserRouter(
<Route path='/signup' lazy={() => import('@/pages/auth/SignUp')} />
<Route path='/forgot-password' lazy={() => import('@/pages/auth/ForgotPassword')} />
<Route path="/" element={<ProtectedRoute />} errorElement={<ErrorPage />}>
<Route path="/" element={<ChannelRedirect />}>
<Route path="channel" element={<MainPage />} >
<Route path="/" element={<WorkspaceSwitcher />}>
<Route index element={lastWorkspace && lastChannel ? <Navigate to={`/${lastWorkspace}/${lastChannel}`} replace /> : lastWorkspace ? <Navigate to={`/${lastWorkspace}`} replace /> : <WorkspaceSwitcherGrid />} />
<Route path="workspace-explorer" element={<WorkspaceSwitcherGrid />} />
<Route path="settings" lazy={() => import('./pages/settings/Settings')}>
<Route index lazy={() => import('./components/feature/userSettings/UserProfile/UserProfile')} />
<Route path="profile" lazy={() => import('./components/feature/userSettings/UserProfile/UserProfile')} />
<Route path="users" lazy={() => import('./pages/settings/Users/UserList')} />
<Route path="appearance" lazy={() => import('./pages/settings/Appearance')} />
<Route path="hr" lazy={() => import('./pages/settings/Integrations/FrappeHR')} />

<Route path="workspaces" >
<Route index lazy={() => import('./pages/settings/Workspaces/WorkspaceList')} />
<Route path=":ID" lazy={() => import('./pages/settings/Workspaces/ViewWorkspace')} />
</Route>

<Route path="bots" >
<Route index lazy={() => import('./pages/settings/AI/BotList')} />
<Route path="create" lazy={() => import('./pages/settings/AI/CreateBot')} />
<Route path=":ID" lazy={() => import('./pages/settings/AI/ViewBot')} />
</Route>

<Route path="functions">
<Route index lazy={() => import('./pages/settings/AI/FunctionList')} />
<Route path="create" lazy={() => import('./pages/settings/AI/CreateFunction')} />
<Route path=":ID" lazy={() => import('./pages/settings/AI/ViewFunction')} />
</Route>


<Route path="instructions">
<Route index lazy={() => import('./pages/settings/AI/InstructionTemplateList')} />
<Route path="create" lazy={() => import('./pages/settings/AI/CreateInstructionTemplate')} />
<Route path=":ID" lazy={() => import('./pages/settings/AI/ViewInstructionTemplate')} />
</Route>

<Route path="commands">
<Route index lazy={() => import('./pages/settings/AI/SavedPromptsList')} />
<Route path="create" lazy={() => import('./pages/settings/AI/CreateSavedPrompt')} />
<Route path=":ID" lazy={() => import('./pages/settings/AI/ViewSavedPrompt')} />
</Route>

<Route path="openai-settings" lazy={() => import('./pages/settings/AI/OpenAISettings')} />

<Route path="webhooks">
<Route index lazy={() => import('./pages/settings/Webhooks/WebhookList')} />
<Route path="create" lazy={() => import('./pages/settings/Webhooks/CreateWebhook')} />
<Route path=":ID" lazy={() => import('./pages/settings/Webhooks/ViewWebhook')} />
</Route>

<Route path="scheduled-messages">
<Route index lazy={() => import('./pages/settings/ServerScripts/SchedulerEvents/SchedulerEvents')} />
<Route path="create" lazy={() => import('./pages/settings/ServerScripts/SchedulerEvents/CreateSchedulerEvent')} />
<Route path=":ID" lazy={() => import('./pages/settings/ServerScripts/SchedulerEvents/ViewSchedulerEvent')} />
</Route>

<Route path="message-actions">
<Route index lazy={() => import('./pages/settings/MessageActions/MessageActionList')} />
<Route path="create" lazy={() => import('./pages/settings/MessageActions/CreateMessageAction')} />
<Route path=":ID" lazy={() => import('./pages/settings/MessageActions/ViewMessageAction')} />
</Route>
</Route>
<Route path=":workspaceID" element={<MainPage />}>
<Route index element={<MobileTabsPage />} />
<Route path="threads" lazy={() => import('./components/feature/threads/Threads')}>
<Route path="thread/:threadID" lazy={() => import('./components/feature/threads/ThreadDrawer/ThreadDrawer')} />
</Route>
<Route path="saved-messages" lazy={() => import('./components/feature/saved-messages/SavedMessages')} />
<Route path="settings" lazy={() => import('./pages/settings/Settings')}>
<Route index lazy={() => import('./components/feature/userSettings/UserProfile/UserProfile')} />
<Route path="profile" lazy={() => import('./components/feature/userSettings/UserProfile/UserProfile')} />
<Route path="users" lazy={() => import('./pages/settings/Users/UserList')} />
<Route path="appearance" lazy={() => import('./pages/settings/Appearance')} />
<Route path="hr" lazy={() => import('./pages/settings/Integrations/FrappeHR')} />
<Route path="bots" >
<Route index lazy={() => import('./pages/settings/AI/BotList')} />
<Route path="create" lazy={() => import('./pages/settings/AI/CreateBot')} />
<Route path=":ID" lazy={() => import('./pages/settings/AI/ViewBot')} />
</Route>

<Route path="functions">
<Route index lazy={() => import('./pages/settings/AI/FunctionList')} />
<Route path="create" lazy={() => import('./pages/settings/AI/CreateFunction')} />
<Route path=":ID" lazy={() => import('./pages/settings/AI/ViewFunction')} />
</Route>


<Route path="instructions">
<Route index lazy={() => import('./pages/settings/AI/InstructionTemplateList')} />
<Route path="create" lazy={() => import('./pages/settings/AI/CreateInstructionTemplate')} />
<Route path=":ID" lazy={() => import('./pages/settings/AI/ViewInstructionTemplate')} />
</Route>

<Route path="commands">
<Route index lazy={() => import('./pages/settings/AI/SavedPromptsList')} />
<Route path="create" lazy={() => import('./pages/settings/AI/CreateSavedPrompt')} />
<Route path=":ID" lazy={() => import('./pages/settings/AI/ViewSavedPrompt')} />
</Route>

<Route path="openai-settings" lazy={() => import('./pages/settings/AI/OpenAISettings')} />

<Route path="webhooks">
<Route index lazy={() => import('./pages/settings/Webhooks/WebhookList')} />
<Route path="create" lazy={() => import('./pages/settings/Webhooks/CreateWebhook')} />
<Route path=":ID" lazy={() => import('./pages/settings/Webhooks/ViewWebhook')} />
</Route>

<Route path="scheduled-messages">
<Route index lazy={() => import('./pages/settings/ServerScripts/SchedulerEvents/SchedulerEvents')} />
<Route path="create" lazy={() => import('./pages/settings/ServerScripts/SchedulerEvents/CreateSchedulerEvent')} />
<Route path=":ID" lazy={() => import('./pages/settings/ServerScripts/SchedulerEvents/ViewSchedulerEvent')} />
</Route>

<Route path="message-actions">
<Route index lazy={() => import('./pages/settings/MessageActions/MessageActionList')} />
<Route path="create" lazy={() => import('./pages/settings/MessageActions/CreateMessageAction')} />
<Route path=":ID" lazy={() => import('./pages/settings/MessageActions/ViewMessageAction')} />
</Route>
</Route>

<Route path=":channelID" lazy={() => import('@/pages/ChatSpace')}>
<Route path="thread/:threadID" lazy={() => import('./components/feature/threads/ThreadDrawer/ThreadDrawer')} />
</Route>
Expand Down Expand Up @@ -123,7 +137,7 @@ function App() {
socketPort={import.meta.env.VITE_SOCKET_PORT ? import.meta.env.VITE_SOCKET_PORT : undefined}
//@ts-ignore
swrConfig={{
provider: localStorageProvider
errorRetryCount: 2,
}}
siteName={getSiteName()}
>
Expand Down
14 changes: 5 additions & 9 deletions frontend/src/components/common/Callouts/CustomCallout.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import { Callout } from "@radix-ui/themes";
import {
CalloutIconProps,
CalloutRootProps,
CalloutTextProps,
} from "@radix-ui/themes/dist/cjs/components/callout";
import clsx from "clsx";
import { PropsWithChildren } from "react";

export type CalloutObject = {
Expand All @@ -12,10 +8,10 @@ export type CalloutObject = {
}

export type CustomCalloutProps = {
rootProps?: CalloutRootProps;
iconProps?: CalloutIconProps;
rootProps?: Callout.RootProps;
iconProps?: Callout.IconProps;
iconChildren?: React.ReactNode;
textProps?: CalloutTextProps;
textProps?: Callout.TextProps;
textChildren?: React.ReactNode;
};

Expand All @@ -27,7 +23,7 @@ export const CustomCallout = ({
iconChildren,
}: PropsWithChildren<CustomCalloutProps>) => {
return (
<Callout.Root {...rootProps}>
<Callout.Root {...rootProps} className={clsx("animate-fadein", rootProps?.className)}>
<Callout.Icon {...iconProps}>{iconChildren}</Callout.Icon>
<Callout.Text {...textProps}>{textChildren}</Callout.Text>
</Callout.Root>
Expand Down
15 changes: 10 additions & 5 deletions frontend/src/components/common/LinkField/LinkField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useCombobox } from "downshift";
import { Filter, SearchResult, useSearch } from "frappe-react-sdk";
import { useState } from "react";
import { Label } from "../Form";
import { Text, TextField } from "@radix-ui/themes";
import { Text, TextField, VisuallyHidden } from "@radix-ui/themes";
import { useIsDesktop } from "@/hooks/useMediaQuery";
import clsx from "clsx";

Expand All @@ -20,10 +20,11 @@ export interface LinkFieldProps {
dropdownClass?: string,
required?: boolean,
suggestedItems?: SearchResult[],
hideLabel?: boolean
}


const LinkField = ({ doctype, filters, label, placeholder, value, required, setValue, disabled, autofocus, dropdownClass, suggestedItems }: LinkFieldProps) => {
const LinkField = ({ doctype, filters, hideLabel = false, label, placeholder, value, required, setValue, disabled, autofocus, dropdownClass, suggestedItems }: LinkFieldProps) => {

const [searchText, setSearchText] = useState(value ?? '')

Expand Down Expand Up @@ -63,9 +64,13 @@ const LinkField = ({ doctype, filters, label, placeholder, value, required, setV

return <div className="w-full">
<div className="flex flex-col">
<Label className="w-fit" isRequired={required} {...getLabelProps()}>
{label}
</Label>
{hideLabel ? <VisuallyHidden>
<Label isRequired={required} {...getLabelProps()}></Label>
</VisuallyHidden> :
<Label className="w-fit" isRequired={required} {...getLabelProps()}>
{label}
</Label>
}
<TextField.Root
placeholder={placeholder ?? `Search ${doctype}`}
className='w-full'
Expand Down
1 change: 1 addition & 0 deletions frontend/src/components/common/LinkField/LinkFormField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const LinkFormField = ({ name, rules, ...linkFieldProps }: LinkFormFieldProps) =
render={({ field }) => (
<LinkField
value={field.value}
disabled={field.disabled}
setValue={field.onChange}
{...linkFieldProps}
/>
Expand Down
6 changes: 4 additions & 2 deletions frontend/src/components/common/Loader.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
export const Loader = () => {
import clsx from "clsx"

export const Loader = ({ className }: { className?: string }) => {
return (
<svg className="animate-spin h-4 w-4 dark:text-white text-gray-900" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<svg className={clsx("animate-spin h-4 w-4 dark:text-white text-gray-900", className)} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
Expand Down
Loading
Loading