mirror of https://github.com/langgenius/dify.git
refactor(web): migrate members invite overlays to base ui (#33922)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
edb261bc90
commit
dc1a68661c
|
|
@ -78,6 +78,7 @@ const ApiBasedExtensionModal: FC<ApiBasedExtensionModalProps> = ({
|
|||
<Modal
|
||||
isShow
|
||||
onClose={noop}
|
||||
wrapperClassName="z-[1002]"
|
||||
className="!w-[640px] !max-w-none !p-8 !pb-6"
|
||||
>
|
||||
<div className="mb-2 text-xl font-semibold text-text-primary">
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ const ApiBasedExtensionSelector: FC<ApiBasedExtensionSelectorProps> = ({
|
|||
)
|
||||
}
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className="z-[102] w-[calc(100%-32px)] max-w-[576px]">
|
||||
<PortalToFollowElemContent className="z-[1002] w-[calc(100%-32px)] max-w-[576px]">
|
||||
<div className="z-10 w-full rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-lg">
|
||||
<div className="p-1">
|
||||
<div className="flex items-center justify-between px-3 pb-1 pt-2">
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ const Configure = ({
|
|||
{t('dataSource.configure', { ns: 'common' })}
|
||||
</Button>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className="z-[61]">
|
||||
<PortalToFollowElemContent className="z-[1002]">
|
||||
<div className="w-[240px] space-y-1.5 rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-2 shadow-lg">
|
||||
{
|
||||
!!canOAuth && (
|
||||
|
|
@ -104,7 +104,7 @@ const Configure = ({
|
|||
}
|
||||
{
|
||||
!!canApiKey && !!canOAuth && (
|
||||
<div className="system-2xs-medium-uppercase flex h-4 items-center p-2 text-text-quaternary">
|
||||
<div className="flex h-4 items-center p-2 text-text-quaternary system-2xs-medium-uppercase">
|
||||
<div className="mr-2 h-[1px] grow bg-gradient-to-l from-[rgba(16,24,40,0.08)]" />
|
||||
OR
|
||||
<div className="ml-2 h-[1px] grow bg-gradient-to-r from-[rgba(16,24,40,0.08)]" />
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ const Operator = ({
|
|||
text: (
|
||||
<div className="flex items-center">
|
||||
<RiHome9Line className="mr-2 h-4 w-4 text-text-tertiary" />
|
||||
<div className="system-sm-semibold text-text-secondary">{t('auth.setDefault', { ns: 'plugin' })}</div>
|
||||
<div className="text-text-secondary system-sm-semibold">{t('auth.setDefault', { ns: 'plugin' })}</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
|
|
@ -51,7 +51,7 @@ const Operator = ({
|
|||
text: (
|
||||
<div className="flex items-center">
|
||||
<RiEditLine className="mr-2 h-4 w-4 text-text-tertiary" />
|
||||
<div className="system-sm-semibold text-text-secondary">{t('operation.rename', { ns: 'common' })}</div>
|
||||
<div className="text-text-secondary system-sm-semibold">{t('operation.rename', { ns: 'common' })}</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
|
|
@ -66,7 +66,7 @@ const Operator = ({
|
|||
text: (
|
||||
<div className="flex items-center">
|
||||
<RiEqualizer2Line className="mr-2 h-4 w-4 text-text-tertiary" />
|
||||
<div className="system-sm-semibold text-text-secondary">{t('operation.edit', { ns: 'common' })}</div>
|
||||
<div className="text-text-secondary system-sm-semibold">{t('operation.edit', { ns: 'common' })}</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
|
|
@ -81,7 +81,7 @@ const Operator = ({
|
|||
text: (
|
||||
<div className="flex items-center">
|
||||
<RiStickyNoteAddLine className="mr-2 h-4 w-4 text-text-tertiary" />
|
||||
<div className="system-sm-semibold mb-1 text-text-secondary">{t('dataSource.notion.changeAuthorizedPages', { ns: 'common' })}</div>
|
||||
<div className="mb-1 text-text-secondary system-sm-semibold">{t('dataSource.notion.changeAuthorizedPages', { ns: 'common' })}</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
|
|
@ -98,7 +98,7 @@ const Operator = ({
|
|||
text: (
|
||||
<div className="flex items-center">
|
||||
<RiDeleteBinLine className="mr-2 h-4 w-4 text-text-tertiary" />
|
||||
<div className="system-sm-semibold text-text-secondary">
|
||||
<div className="text-text-secondary system-sm-semibold">
|
||||
{t('operation.remove', { ns: 'common' })}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -122,7 +122,7 @@ const Operator = ({
|
|||
items={items}
|
||||
secondItems={secondItems}
|
||||
onSelect={handleSelect}
|
||||
popupClassName="z-[61]"
|
||||
popupClassName="z-[1002]"
|
||||
triggerProps={{
|
||||
size: 'l',
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,15 @@ import type { InvitationResponse } from '@/models/common'
|
|||
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { vi } from 'vitest'
|
||||
import { ToastContext } from '@/app/components/base/toast/context'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import { useProviderContextSelector } from '@/context/provider-context'
|
||||
import { inviteMember } from '@/service/common'
|
||||
import InviteModal from '../index'
|
||||
|
||||
const { mockToastError } = vi.hoisted(() => ({
|
||||
mockToastError: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock('@/context/provider-context', () => ({
|
||||
useProviderContextSelector: vi.fn(),
|
||||
useProviderContext: vi.fn(() => ({
|
||||
|
|
@ -14,6 +18,11 @@ vi.mock('@/context/provider-context', () => ({
|
|||
})),
|
||||
}))
|
||||
vi.mock('@/service/common')
|
||||
vi.mock('@/app/components/base/ui/toast', () => ({
|
||||
toast: {
|
||||
error: mockToastError,
|
||||
},
|
||||
}))
|
||||
vi.mock('@/context/i18n', () => ({
|
||||
useLocale: () => 'en-US',
|
||||
}))
|
||||
|
|
@ -37,7 +46,6 @@ describe('InviteModal', () => {
|
|||
const mockOnCancel = vi.fn()
|
||||
const mockOnSend = vi.fn()
|
||||
const mockRefreshLicenseLimit = vi.fn()
|
||||
const mockNotify = vi.fn()
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
|
|
@ -49,10 +57,11 @@ describe('InviteModal', () => {
|
|||
})
|
||||
|
||||
const renderModal = (isEmailSetup = true) => render(
|
||||
<ToastContext.Provider value={{ notify: mockNotify, close: vi.fn() }}>
|
||||
<InviteModal isEmailSetup={isEmailSetup} onCancel={mockOnCancel} onSend={mockOnSend} />
|
||||
</ToastContext.Provider>,
|
||||
<InviteModal isEmailSetup={isEmailSetup} onCancel={mockOnCancel} onSend={mockOnSend} />,
|
||||
)
|
||||
const fillEmails = (value: string) => {
|
||||
fireEvent.change(screen.getByTestId('mock-email-input'), { target: { value } })
|
||||
}
|
||||
|
||||
it('should render invite modal content', async () => {
|
||||
renderModal()
|
||||
|
|
@ -68,12 +77,8 @@ describe('InviteModal', () => {
|
|||
})
|
||||
|
||||
it('should enable send button after entering an email', async () => {
|
||||
const user = userEvent.setup()
|
||||
|
||||
renderModal()
|
||||
|
||||
const input = screen.getByTestId('mock-email-input')
|
||||
await user.type(input, 'user@example.com')
|
||||
fillEmails('user@example.com')
|
||||
|
||||
expect(screen.getByRole('button', { name: /members\.sendInvite/i })).toBeEnabled()
|
||||
})
|
||||
|
|
@ -84,7 +89,7 @@ describe('InviteModal', () => {
|
|||
|
||||
renderModal()
|
||||
|
||||
await user.type(screen.getByTestId('mock-email-input'), 'user@example.com')
|
||||
fillEmails('user@example.com')
|
||||
await user.click(screen.getByRole('button', { name: /members\.sendInvite/i }))
|
||||
|
||||
await waitFor(() => {
|
||||
|
|
@ -103,8 +108,7 @@ describe('InviteModal', () => {
|
|||
|
||||
renderModal()
|
||||
|
||||
const input = screen.getByTestId('mock-email-input')
|
||||
await user.type(input, 'user@example.com')
|
||||
fillEmails('user@example.com')
|
||||
await user.click(screen.getByRole('button', { name: /members\.sendInvite/i }))
|
||||
|
||||
await waitFor(() => {
|
||||
|
|
@ -116,8 +120,6 @@ describe('InviteModal', () => {
|
|||
})
|
||||
|
||||
it('should keep send button disabled when license limit is exceeded', async () => {
|
||||
const user = userEvent.setup()
|
||||
|
||||
vi.mocked(useProviderContextSelector).mockImplementation(selector => selector({
|
||||
licenseLimit: { workspace_members: { size: 10, limit: 10 } },
|
||||
refreshLicenseLimit: mockRefreshLicenseLimit,
|
||||
|
|
@ -125,8 +127,7 @@ describe('InviteModal', () => {
|
|||
|
||||
renderModal()
|
||||
|
||||
const input = screen.getByTestId('mock-email-input')
|
||||
await user.type(input, 'user@example.com')
|
||||
fillEmails('user@example.com')
|
||||
|
||||
expect(screen.getByRole('button', { name: /members\.sendInvite/i })).toBeDisabled()
|
||||
})
|
||||
|
|
@ -144,15 +145,11 @@ describe('InviteModal', () => {
|
|||
const user = userEvent.setup()
|
||||
renderModal()
|
||||
|
||||
const input = screen.getByTestId('mock-email-input')
|
||||
// Use an email that passes basic validation but fails our strict regex (needs 2+ char TLD)
|
||||
await user.type(input, 'invalid@email.c')
|
||||
fillEmails('invalid@email.c')
|
||||
await user.click(screen.getByRole('button', { name: /members\.sendInvite/i }))
|
||||
|
||||
expect(mockNotify).toHaveBeenCalledWith({
|
||||
type: 'error',
|
||||
message: 'common.members.emailInvalid',
|
||||
})
|
||||
expect(toast.error).toHaveBeenCalledWith('common.members.emailInvalid')
|
||||
expect(inviteMember).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
|
|
@ -160,8 +157,7 @@ describe('InviteModal', () => {
|
|||
const user = userEvent.setup()
|
||||
renderModal()
|
||||
|
||||
const input = screen.getByTestId('mock-email-input')
|
||||
await user.type(input, 'user@example.com')
|
||||
fillEmails('user@example.com')
|
||||
|
||||
expect(screen.getByText('user@example.com')).toBeInTheDocument()
|
||||
|
||||
|
|
@ -203,7 +199,7 @@ describe('InviteModal', () => {
|
|||
|
||||
renderModal()
|
||||
|
||||
await user.type(screen.getByTestId('mock-email-input'), 'user@example.com')
|
||||
fillEmails('user@example.com')
|
||||
await user.click(screen.getByRole('button', { name: /members\.sendInvite/i }))
|
||||
|
||||
await waitFor(() => {
|
||||
|
|
@ -214,8 +210,6 @@ describe('InviteModal', () => {
|
|||
})
|
||||
|
||||
it('should show destructive text color when used size exceeds limit', async () => {
|
||||
const user = userEvent.setup()
|
||||
|
||||
vi.mocked(useProviderContextSelector).mockImplementation(selector => selector({
|
||||
licenseLimit: { workspace_members: { size: 10, limit: 10 } },
|
||||
refreshLicenseLimit: mockRefreshLicenseLimit,
|
||||
|
|
@ -223,8 +217,7 @@ describe('InviteModal', () => {
|
|||
|
||||
renderModal()
|
||||
|
||||
const input = screen.getByTestId('mock-email-input')
|
||||
await user.type(input, 'user@example.com')
|
||||
fillEmails('user@example.com')
|
||||
|
||||
// usedSize = 10 + 1 = 11 > limit 10 → destructive color
|
||||
const counter = screen.getByText('11')
|
||||
|
|
@ -241,8 +234,7 @@ describe('InviteModal', () => {
|
|||
|
||||
renderModal()
|
||||
|
||||
const input = screen.getByTestId('mock-email-input')
|
||||
await user.type(input, 'user@example.com')
|
||||
fillEmails('user@example.com')
|
||||
|
||||
const sendBtn = screen.getByRole('button', { name: /members\.sendInvite/i })
|
||||
|
||||
|
|
@ -264,8 +256,6 @@ describe('InviteModal', () => {
|
|||
})
|
||||
|
||||
it('should show destructive color and disable send button when limit is exactly met with one email', async () => {
|
||||
const user = userEvent.setup()
|
||||
|
||||
// size=10, limit=10 - adding 1 email makes usedSize=11 > limit=10
|
||||
vi.mocked(useProviderContextSelector).mockImplementation(selector => selector({
|
||||
licenseLimit: { workspace_members: { size: 10, limit: 10 } },
|
||||
|
|
@ -274,8 +264,7 @@ describe('InviteModal', () => {
|
|||
|
||||
renderModal()
|
||||
|
||||
const input = screen.getByTestId('mock-email-input')
|
||||
await user.type(input, 'user@example.com')
|
||||
fillEmails('user@example.com')
|
||||
|
||||
// isLimitExceeded=true → button is disabled, cannot submit
|
||||
const sendBtn = screen.getByRole('button', { name: /members\.sendInvite/i })
|
||||
|
|
@ -293,8 +282,7 @@ describe('InviteModal', () => {
|
|||
|
||||
renderModal()
|
||||
|
||||
const input = screen.getByTestId('mock-email-input')
|
||||
await user.type(input, 'user@example.com')
|
||||
fillEmails('user@example.com')
|
||||
|
||||
const sendBtn = screen.getByRole('button', { name: /members\.sendInvite/i })
|
||||
|
||||
|
|
@ -320,11 +308,9 @@ describe('InviteModal', () => {
|
|||
refreshLicenseLimit: mockRefreshLicenseLimit,
|
||||
} as unknown as Parameters<typeof selector>[0]))
|
||||
|
||||
const user = userEvent.setup()
|
||||
renderModal()
|
||||
|
||||
const input = screen.getByTestId('mock-email-input')
|
||||
await user.type(input, 'user@example.com')
|
||||
fillEmails('user@example.com')
|
||||
|
||||
// isLimited=false → no destructive color
|
||||
const counter = screen.getByText('1')
|
||||
|
|
|
|||
|
|
@ -1,12 +0,0 @@
|
|||
.modal {
|
||||
padding: 24px 32px !important;
|
||||
width: 400px !important;
|
||||
}
|
||||
|
||||
.emailsInput {
|
||||
background-color: rgb(243 244 246 / var(--tw-bg-opacity)) !important;
|
||||
}
|
||||
|
||||
.emailBackground {
|
||||
background-color: white !important;
|
||||
}
|
||||
|
|
@ -2,20 +2,17 @@
|
|||
import type { RoleKey } from './role-selector'
|
||||
import type { InvitationResult } from '@/models/common'
|
||||
import { useBoolean } from 'ahooks'
|
||||
import { noop } from 'es-toolkit/function'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { ReactMultiEmail } from 'react-multi-email'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import Button from '@/app/components/base/button'
|
||||
import Modal from '@/app/components/base/modal'
|
||||
import { ToastContext } from '@/app/components/base/toast/context'
|
||||
import { Dialog, DialogCloseButton, DialogContent, DialogTitle } from '@/app/components/base/ui/dialog'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import { emailRegex } from '@/config'
|
||||
import { useLocale } from '@/context/i18n'
|
||||
import { useProviderContextSelector } from '@/context/provider-context'
|
||||
import { inviteMember } from '@/service/common'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import s from './index.module.css'
|
||||
import RoleSelector from './role-selector'
|
||||
import 'react-multi-email/dist/style.css'
|
||||
|
||||
|
|
@ -34,7 +31,6 @@ const InviteModal = ({
|
|||
const licenseLimit = useProviderContextSelector(s => s.licenseLimit)
|
||||
const refreshLicenseLimit = useProviderContextSelector(s => s.refreshLicenseLimit)
|
||||
const [emails, setEmails] = useState<string[]>([])
|
||||
const { notify } = useContext(ToastContext)
|
||||
const [isLimited, setIsLimited] = useState(false)
|
||||
const [isLimitExceeded, setIsLimitExceeded] = useState(false)
|
||||
const [usedSize, setUsedSize] = useState(licenseLimit.workspace_members.size ?? 0)
|
||||
|
|
@ -74,21 +70,28 @@ const InviteModal = ({
|
|||
catch { }
|
||||
}
|
||||
else {
|
||||
notify({ type: 'error', message: t('members.emailInvalid', { ns: 'common' }) })
|
||||
toast.error(t('members.emailInvalid', { ns: 'common' }))
|
||||
}
|
||||
setIsSubmitted()
|
||||
}, [isLimitExceeded, emails, role, locale, onCancel, onSend, notify, t, isSubmitting, refreshLicenseLimit, setIsSubmitted, setIsSubmitting])
|
||||
}, [isLimitExceeded, emails, role, locale, onCancel, onSend, t, isSubmitting, refreshLicenseLimit, setIsSubmitted, setIsSubmitting])
|
||||
|
||||
return (
|
||||
<div className={cn(s.wrap)}>
|
||||
<Modal overflowVisible isShow onClose={noop} className={cn(s.modal)}>
|
||||
<div className="mb-2 flex justify-between">
|
||||
<div className="text-xl font-semibold text-text-primary">{t('members.inviteTeamMember', { ns: 'common' })}</div>
|
||||
<div
|
||||
data-testid="invite-modal-close"
|
||||
className="i-ri-close-line h-4 w-4 cursor-pointer text-text-tertiary"
|
||||
onClick={onCancel}
|
||||
/>
|
||||
<Dialog
|
||||
open
|
||||
onOpenChange={(open) => {
|
||||
if (!open)
|
||||
onCancel()
|
||||
}}
|
||||
>
|
||||
<DialogContent
|
||||
backdropProps={{ forceRender: true }}
|
||||
className="w-[400px] overflow-visible px-8 py-6"
|
||||
>
|
||||
<DialogCloseButton data-testid="invite-modal-close" className="right-8 top-6" />
|
||||
<div className="mb-2 pr-8">
|
||||
<DialogTitle className="text-xl font-semibold text-text-primary">
|
||||
{t('members.inviteTeamMember', { ns: 'common' })}
|
||||
</DialogTitle>
|
||||
</div>
|
||||
<div className="mb-3 text-[13px] text-text-tertiary">{t('members.inviteTeamMemberTip', { ns: 'common' })}</div>
|
||||
{!isEmailSetup && (
|
||||
|
|
@ -152,8 +155,8 @@ const InviteModal = ({
|
|||
{t('members.sendInvite', { ns: 'common' })}
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
import * as React from 'react'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from '@/app/components/base/ui/popover'
|
||||
import { useProviderContext } from '@/context/provider-context'
|
||||
import { cn } from '@/utils/classnames'
|
||||
|
||||
|
|
@ -25,115 +24,111 @@ export type RoleSelectorProps = {
|
|||
|
||||
const RoleSelector = ({ value, onChange }: RoleSelectorProps) => {
|
||||
const { t } = useTranslation()
|
||||
const [open, setOpen] = useState(false)
|
||||
const { datasetOperatorEnabled } = useProviderContext()
|
||||
const [open, setOpen] = React.useState(false)
|
||||
|
||||
return (
|
||||
<PortalToFollowElem
|
||||
<Popover
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
placement="bottom-start"
|
||||
offset={4}
|
||||
>
|
||||
<div className="relative">
|
||||
<PortalToFollowElemTrigger
|
||||
onClick={() => setOpen(v => !v)}
|
||||
className="block"
|
||||
>
|
||||
<PopoverTrigger
|
||||
data-testid="role-selector-trigger"
|
||||
className={cn(
|
||||
'flex w-full cursor-pointer items-center rounded-lg bg-components-input-bg-normal px-3 py-2 hover:bg-state-base-hover',
|
||||
open && 'bg-state-base-hover',
|
||||
)}
|
||||
>
|
||||
<div className="mr-2 grow text-sm leading-5 text-text-primary">{t('members.invitedAsRole', { ns: 'common', role: t(roleI18nKeyMap[value], { ns: 'common' }) })}</div>
|
||||
<div className="i-ri-arrow-down-s-line h-4 w-4 shrink-0 text-text-secondary" />
|
||||
</PopoverTrigger>
|
||||
<PopoverContent
|
||||
placement="bottom-start"
|
||||
sideOffset={4}
|
||||
popupClassName="w-[336px] rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-lg"
|
||||
>
|
||||
<div className="p-1">
|
||||
<div
|
||||
data-testid="role-selector-trigger"
|
||||
className={cn('flex cursor-pointer items-center rounded-lg bg-components-input-bg-normal px-3 py-2 hover:bg-state-base-hover', open && 'bg-state-base-hover')}
|
||||
data-testid="role-option-normal"
|
||||
className="cursor-pointer rounded-lg p-2 hover:bg-state-base-hover"
|
||||
onClick={() => {
|
||||
onChange('normal')
|
||||
setOpen(false)
|
||||
}}
|
||||
>
|
||||
<div className="mr-2 grow text-sm leading-5 text-text-primary">{t('members.invitedAsRole', { ns: 'common', role: t(roleI18nKeyMap[value], { ns: 'common' }) })}</div>
|
||||
<div className="i-ri-arrow-down-s-line h-4 w-4 shrink-0 text-text-secondary" />
|
||||
</div>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className="z-[1002]">
|
||||
<div className="relative w-[336px] rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-lg">
|
||||
<div className="p-1">
|
||||
<div
|
||||
data-testid="role-option-normal"
|
||||
className="cursor-pointer rounded-lg p-2 hover:bg-state-base-hover"
|
||||
onClick={() => {
|
||||
onChange('normal')
|
||||
setOpen(false)
|
||||
}}
|
||||
>
|
||||
<div className="relative pl-5">
|
||||
<div className="text-sm leading-5 text-text-secondary">{t('members.normal', { ns: 'common' })}</div>
|
||||
<div className="text-xs leading-[18px] text-text-tertiary">{t('members.normalTip', { ns: 'common' })}</div>
|
||||
{value === 'normal' && (
|
||||
<div
|
||||
data-testid="role-option-check"
|
||||
className="i-custom-vender-line-general-check absolute left-0 top-0.5 h-4 w-4 text-text-accent"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
data-testid="role-option-editor"
|
||||
className="cursor-pointer rounded-lg p-2 hover:bg-state-base-hover"
|
||||
onClick={() => {
|
||||
onChange('editor')
|
||||
setOpen(false)
|
||||
}}
|
||||
>
|
||||
<div className="relative pl-5">
|
||||
<div className="text-sm leading-5 text-text-secondary">{t('members.editor', { ns: 'common' })}</div>
|
||||
<div className="text-xs leading-[18px] text-text-tertiary">{t('members.editorTip', { ns: 'common' })}</div>
|
||||
{value === 'editor' && (
|
||||
<div
|
||||
data-testid="role-option-check"
|
||||
className="i-custom-vender-line-general-check absolute left-0 top-0.5 h-4 w-4 text-text-accent"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
data-testid="role-option-admin"
|
||||
className="cursor-pointer rounded-lg p-2 hover:bg-state-base-hover"
|
||||
onClick={() => {
|
||||
onChange('admin')
|
||||
setOpen(false)
|
||||
}}
|
||||
>
|
||||
<div className="relative pl-5">
|
||||
<div className="text-sm leading-5 text-text-secondary">{t('members.admin', { ns: 'common' })}</div>
|
||||
<div className="text-xs leading-[18px] text-text-tertiary">{t('members.adminTip', { ns: 'common' })}</div>
|
||||
{value === 'admin' && (
|
||||
<div
|
||||
data-testid="role-option-check"
|
||||
className="i-custom-vender-line-general-check absolute left-0 top-0.5 h-4 w-4 text-text-accent"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{datasetOperatorEnabled && (
|
||||
<div className="relative pl-5">
|
||||
<div className="text-sm leading-5 text-text-secondary">{t('members.normal', { ns: 'common' })}</div>
|
||||
<div className="text-xs leading-[18px] text-text-tertiary">{t('members.normalTip', { ns: 'common' })}</div>
|
||||
{value === 'normal' && (
|
||||
<div
|
||||
data-testid="role-option-dataset_operator"
|
||||
className="cursor-pointer rounded-lg p-2 hover:bg-state-base-hover"
|
||||
onClick={() => {
|
||||
onChange('dataset_operator')
|
||||
setOpen(false)
|
||||
}}
|
||||
>
|
||||
<div className="relative pl-5">
|
||||
<div className="text-sm leading-5 text-text-secondary">{t('members.datasetOperator', { ns: 'common' })}</div>
|
||||
<div className="text-xs leading-[18px] text-text-tertiary">{t('members.datasetOperatorTip', { ns: 'common' })}</div>
|
||||
{value === 'dataset_operator' && (
|
||||
<div
|
||||
data-testid="role-option-check"
|
||||
className="i-custom-vender-line-general-check absolute left-0 top-0.5 h-4 w-4 text-text-accent"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
data-testid="role-option-check"
|
||||
className="i-custom-vender-line-general-check absolute left-0 top-0.5 h-4 w-4 text-text-accent"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
</div>
|
||||
</PortalToFollowElem>
|
||||
<div
|
||||
data-testid="role-option-editor"
|
||||
className="cursor-pointer rounded-lg p-2 hover:bg-state-base-hover"
|
||||
onClick={() => {
|
||||
onChange('editor')
|
||||
setOpen(false)
|
||||
}}
|
||||
>
|
||||
<div className="relative pl-5">
|
||||
<div className="text-sm leading-5 text-text-secondary">{t('members.editor', { ns: 'common' })}</div>
|
||||
<div className="text-xs leading-[18px] text-text-tertiary">{t('members.editorTip', { ns: 'common' })}</div>
|
||||
{value === 'editor' && (
|
||||
<div
|
||||
data-testid="role-option-check"
|
||||
className="i-custom-vender-line-general-check absolute left-0 top-0.5 h-4 w-4 text-text-accent"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
data-testid="role-option-admin"
|
||||
className="cursor-pointer rounded-lg p-2 hover:bg-state-base-hover"
|
||||
onClick={() => {
|
||||
onChange('admin')
|
||||
setOpen(false)
|
||||
}}
|
||||
>
|
||||
<div className="relative pl-5">
|
||||
<div className="text-sm leading-5 text-text-secondary">{t('members.admin', { ns: 'common' })}</div>
|
||||
<div className="text-xs leading-[18px] text-text-tertiary">{t('members.adminTip', { ns: 'common' })}</div>
|
||||
{value === 'admin' && (
|
||||
<div
|
||||
data-testid="role-option-check"
|
||||
className="i-custom-vender-line-general-check absolute left-0 top-0.5 h-4 w-4 text-text-accent"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{datasetOperatorEnabled && (
|
||||
<div
|
||||
data-testid="role-option-dataset_operator"
|
||||
className="cursor-pointer rounded-lg p-2 hover:bg-state-base-hover"
|
||||
onClick={() => {
|
||||
onChange('dataset_operator')
|
||||
setOpen(false)
|
||||
}}
|
||||
>
|
||||
<div className="relative pl-5">
|
||||
<div className="text-sm leading-5 text-text-secondary">{t('members.datasetOperator', { ns: 'common' })}</div>
|
||||
<div className="text-xs leading-[18px] text-text-tertiary">{t('members.datasetOperatorTip', { ns: 'common' })}</div>
|
||||
{value === 'dataset_operator' && (
|
||||
<div
|
||||
data-testid="role-option-check"
|
||||
className="i-custom-vender-line-general-check absolute left-0 top-0.5 h-4 w-4 text-text-accent"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,10 @@
|
|||
import type { InvitationResult } from '@/models/common'
|
||||
import { XMarkIcon } from '@heroicons/react/24/outline'
|
||||
import { CheckCircleIcon } from '@heroicons/react/24/solid'
|
||||
import { RiQuestionLine } from '@remixicon/react'
|
||||
import { noop } from 'es-toolkit/function'
|
||||
import { useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Button from '@/app/components/base/button'
|
||||
import Modal from '@/app/components/base/modal'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import { Dialog, DialogCloseButton, DialogContent, DialogTitle } from '@/app/components/base/ui/dialog'
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/app/components/base/ui/tooltip'
|
||||
import { IS_CE_EDITION } from '@/config'
|
||||
import s from './index.module.css'
|
||||
import InvitationLink from './invitation-link'
|
||||
|
||||
export type SuccessInvitationResult = Extract<InvitationResult, { status: 'success' }>
|
||||
|
|
@ -29,8 +24,18 @@ const InvitedModal = ({
|
|||
const failedInvitationResults = useMemo<FailedInvitationResult[]>(() => invitationResults?.filter(item => item.status !== 'success') as FailedInvitationResult[], [invitationResults])
|
||||
|
||||
return (
|
||||
<div className={s.wrap}>
|
||||
<Modal isShow onClose={noop} className={s.modal}>
|
||||
<Dialog
|
||||
open
|
||||
onOpenChange={(open) => {
|
||||
if (!open)
|
||||
onCancel()
|
||||
}}
|
||||
>
|
||||
<DialogContent
|
||||
backdropProps={{ forceRender: true }}
|
||||
className="w-[480px] p-8"
|
||||
>
|
||||
<DialogCloseButton className="right-8 top-8" />
|
||||
<div className="mb-3 flex justify-between">
|
||||
<div className="
|
||||
flex h-12 w-12 items-center justify-center rounded-xl
|
||||
|
|
@ -38,11 +43,10 @@ const InvitedModal = ({
|
|||
shadow-xl
|
||||
"
|
||||
>
|
||||
<CheckCircleIcon className="h-[22px] w-[22px] text-[#039855]" />
|
||||
<div className="i-heroicons-check-circle-solid h-[22px] w-[22px] text-[#039855]" />
|
||||
</div>
|
||||
<XMarkIcon className="h-4 w-4 cursor-pointer" onClick={onCancel} />
|
||||
</div>
|
||||
<div className="mb-1 text-xl font-semibold text-text-primary">{t('members.invitationSent', { ns: 'common' })}</div>
|
||||
<DialogTitle className="mb-1 text-xl font-semibold text-text-primary">{t('members.invitationSent', { ns: 'common' })}</DialogTitle>
|
||||
{!IS_CE_EDITION && (
|
||||
<div className="mb-10 text-sm text-text-tertiary">{t('members.invitationSentTip', { ns: 'common' })}</div>
|
||||
)}
|
||||
|
|
@ -54,7 +58,7 @@ const InvitedModal = ({
|
|||
!!successInvitationResults.length
|
||||
&& (
|
||||
<>
|
||||
<div className="font-Medium py-2 text-sm text-text-primary">{t('members.invitationLink', { ns: 'common' })}</div>
|
||||
<div className="py-2 text-sm font-medium text-text-primary">{t('members.invitationLink', { ns: 'common' })}</div>
|
||||
{successInvitationResults.map(item =>
|
||||
<InvitationLink key={item.email} value={item} />)}
|
||||
</>
|
||||
|
|
@ -64,18 +68,23 @@ const InvitedModal = ({
|
|||
!!failedInvitationResults.length
|
||||
&& (
|
||||
<>
|
||||
<div className="font-Medium py-2 text-sm text-text-primary">{t('members.failedInvitationEmails', { ns: 'common' })}</div>
|
||||
<div className="py-2 text-sm font-medium text-text-primary">{t('members.failedInvitationEmails', { ns: 'common' })}</div>
|
||||
<div className="flex flex-wrap justify-between gap-y-1">
|
||||
{
|
||||
failedInvitationResults.map(item => (
|
||||
<div key={item.email} className="flex justify-center rounded-md border border-red-300 bg-orange-50 px-1">
|
||||
<Tooltip
|
||||
popupContent={item.message}
|
||||
>
|
||||
<div className="flex items-center justify-center gap-1 text-sm">
|
||||
{item.email}
|
||||
<RiQuestionLine className="h-4 w-4 text-red-300" />
|
||||
</div>
|
||||
<Tooltip>
|
||||
<TooltipTrigger
|
||||
render={(
|
||||
<div className="flex items-center justify-center gap-1 text-sm">
|
||||
{item.email}
|
||||
<div className="i-ri-question-line h-4 w-4 text-red-300" />
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
<TooltipContent>
|
||||
{item.message}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
),
|
||||
|
|
@ -97,8 +106,8 @@ const InvitedModal = ({
|
|||
{t('members.ok', { ns: 'common' })}
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import copy from 'copy-to-clipboard'
|
|||
import { t } from 'i18next'
|
||||
import * as React from 'react'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/app/components/base/ui/tooltip'
|
||||
import s from './index.module.css'
|
||||
|
||||
type IInvitationLinkProps = {
|
||||
|
|
@ -38,20 +38,28 @@ const InvitationLink = ({
|
|||
<div className="flex items-center rounded-lg border border-components-input-border-active bg-components-input-bg-normal py-2 hover:bg-state-base-hover" data-testid="invitation-link-container">
|
||||
<div className="flex h-5 grow items-center">
|
||||
<div className="relative h-full grow text-[13px]">
|
||||
<Tooltip
|
||||
popupContent={isCopied ? `${t('copied', { ns: 'appApi' })}` : `${t('copy', { ns: 'appApi' })}`}
|
||||
>
|
||||
<div className="absolute left-0 right-0 top-0 w-full cursor-pointer truncate pl-2 pr-2 text-text-primary" onClick={copyHandle} data-testid="invitation-link-url">{value.url}</div>
|
||||
<Tooltip>
|
||||
<TooltipTrigger
|
||||
render={<div className="absolute left-0 right-0 top-0 w-full cursor-pointer truncate pl-2 pr-2 text-text-primary" onClick={copyHandle} data-testid="invitation-link-url">{value.url}</div>}
|
||||
/>
|
||||
<TooltipContent>
|
||||
{isCopied ? t('copied', { ns: 'appApi' }) : t('copy', { ns: 'appApi' })}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div className="h-4 shrink-0 border bg-divider-regular" />
|
||||
<Tooltip
|
||||
popupContent={isCopied ? `${t('copied', { ns: 'appApi' })}` : `${t('copy', { ns: 'appApi' })}`}
|
||||
>
|
||||
<div className="shrink-0 px-0.5">
|
||||
<div className={`box-border flex h-[30px] w-[30px] cursor-pointer items-center justify-center rounded-lg hover:bg-state-base-hover ${s.copyIcon} ${isCopied ? s.copied : ''}`} onClick={copyHandle} data-testid="invitation-link-copy">
|
||||
</div>
|
||||
</div>
|
||||
<Tooltip>
|
||||
<TooltipTrigger
|
||||
render={(
|
||||
<div className="shrink-0 px-0.5">
|
||||
<div className={`box-border flex h-[30px] w-[30px] cursor-pointer items-center justify-center rounded-lg hover:bg-state-base-hover ${s.copyIcon} ${isCopied ? s.copied : ''}`} onClick={copyHandle} data-testid="invitation-link-copy">
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
<TooltipContent>
|
||||
{isCopied ? t('copied', { ns: 'appApi' }) : t('copy', { ns: 'appApi' })}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ const Operation = ({
|
|||
<ChevronDownIcon className={cn('h-4 w-4 shrink-0 group-hover:block', open ? 'block' : 'hidden')} />
|
||||
</div>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className="z-[999]">
|
||||
<PortalToFollowElemContent className="z-[1002]">
|
||||
<div className={cn('inline-flex flex-col rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg backdrop-blur-sm')}>
|
||||
<div className="p-1">
|
||||
{
|
||||
|
|
|
|||
|
|
@ -141,6 +141,7 @@ const TransferOwnershipModal = ({ onClose, show }: Props) => {
|
|||
<Modal
|
||||
isShow={show}
|
||||
onClose={noop}
|
||||
wrapperClassName="z-[1002]"
|
||||
className="!w-[420px] !p-6"
|
||||
>
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ const MemberSelector: FC<Props> = ({
|
|||
<div className={cn('i-ri-arrow-down-s-line h-4 w-4 text-text-quaternary group-hover:text-text-secondary', open && 'text-text-secondary')} />
|
||||
</div>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className="z-[1000]">
|
||||
<PortalToFollowElemContent className="z-[1002]">
|
||||
<div className="min-w-[372px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg backdrop-blur-sm">
|
||||
<div className="p-2 pb-1">
|
||||
<Input
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ const AddCustomModel = ({
|
|||
>
|
||||
{renderTrigger(open)}
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className="z-[100]">
|
||||
<PortalToFollowElemContent className="z-[1002]">
|
||||
<div className="w-[320px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg">
|
||||
<div className="max-h-[304px] overflow-y-auto p-1">
|
||||
{
|
||||
|
|
@ -136,7 +136,7 @@ const AddCustomModel = ({
|
|||
modelName={model.model}
|
||||
/>
|
||||
<div
|
||||
className="system-md-regular grow truncate text-text-primary"
|
||||
className="grow truncate text-text-primary system-md-regular"
|
||||
title={model.model}
|
||||
>
|
||||
{model.model}
|
||||
|
|
@ -148,7 +148,7 @@ const AddCustomModel = ({
|
|||
{
|
||||
!notAllowCustomCredential && (
|
||||
<div
|
||||
className="system-xs-medium flex cursor-pointer items-center border-t border-t-divider-subtle p-3 text-text-accent-light-mode-only"
|
||||
className="flex cursor-pointer items-center border-t border-t-divider-subtle p-3 text-text-accent-light-mode-only system-xs-medium"
|
||||
onClick={() => {
|
||||
handleOpenModalForAddNewCustomModel()
|
||||
setOpen(false)
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ const Authorized = ({
|
|||
>
|
||||
{renderTrigger(mergedIsOpen)}
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className="z-[100]">
|
||||
<PortalToFollowElemContent className="z-[1002]">
|
||||
<div className={cn(
|
||||
'w-[360px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg backdrop-blur-[5px]',
|
||||
popupClassName,
|
||||
|
|
@ -172,7 +172,7 @@ const Authorized = ({
|
|||
>
|
||||
{
|
||||
popupTitle && (
|
||||
<div className="system-xs-medium px-3 pb-0.5 pt-[10px] text-text-tertiary">
|
||||
<div className="px-3 pb-0.5 pt-[10px] text-text-tertiary system-xs-medium">
|
||||
{popupTitle}
|
||||
</div>
|
||||
)
|
||||
|
|
@ -218,7 +218,7 @@ const Authorized = ({
|
|||
}
|
||||
: undefined,
|
||||
)}
|
||||
className="system-xs-medium flex h-[40px] cursor-pointer items-center px-3 text-text-accent-light-mode-only"
|
||||
className="flex h-[40px] cursor-pointer items-center px-3 text-text-accent-light-mode-only system-xs-medium"
|
||||
>
|
||||
<RiAddLine className="mr-1 h-4 w-4" />
|
||||
{t('modelProvider.auth.addModelCredential', { ns: 'common' })}
|
||||
|
|
|
|||
|
|
@ -53,14 +53,14 @@ const CredentialSelector = ({
|
|||
triggerPopupSameWidth
|
||||
>
|
||||
<PortalToFollowElemTrigger asChild onClick={() => !disabled && setOpen(v => !v)}>
|
||||
<div className="system-sm-regular flex h-8 w-full items-center justify-between rounded-lg bg-components-input-bg-normal px-2">
|
||||
<div className="flex h-8 w-full items-center justify-between rounded-lg bg-components-input-bg-normal px-2 system-sm-regular">
|
||||
{
|
||||
selectedCredential && (
|
||||
<div className="flex items-center">
|
||||
{
|
||||
!selectedCredential.addNewCredential && <Indicator className="ml-1 mr-2 shrink-0" />
|
||||
}
|
||||
<div className="system-sm-regular truncate text-components-input-text-filled" title={selectedCredential.credential_name}>{selectedCredential.credential_name}</div>
|
||||
<div className="truncate text-components-input-text-filled system-sm-regular" title={selectedCredential.credential_name}>{selectedCredential.credential_name}</div>
|
||||
{
|
||||
selectedCredential.from_enterprise && (
|
||||
<Badge className="shrink-0">Enterprise</Badge>
|
||||
|
|
@ -71,13 +71,13 @@ const CredentialSelector = ({
|
|||
}
|
||||
{
|
||||
!selectedCredential && (
|
||||
<div className="system-sm-regular grow truncate text-components-input-text-placeholder">{t('modelProvider.auth.selectModelCredential', { ns: 'common' })}</div>
|
||||
<div className="grow truncate text-components-input-text-placeholder system-sm-regular">{t('modelProvider.auth.selectModelCredential', { ns: 'common' })}</div>
|
||||
)
|
||||
}
|
||||
<RiArrowDownSLine className="h-4 w-4 text-text-quaternary" />
|
||||
</div>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className="z-[100]">
|
||||
<PortalToFollowElemContent className="z-[1002]">
|
||||
<div className="border-ccomponents-panel-border rounded-xl border-[0.5px] bg-components-panel-bg-blur shadow-lg">
|
||||
<div className="max-h-[320px] overflow-y-auto p-1">
|
||||
{
|
||||
|
|
@ -98,7 +98,7 @@ const CredentialSelector = ({
|
|||
{
|
||||
!notAllowAddNewCredential && (
|
||||
<div
|
||||
className="system-xs-medium flex h-10 cursor-pointer items-center border-t border-t-divider-subtle px-7 text-text-accent-light-mode-only"
|
||||
className="flex h-10 cursor-pointer items-center border-t border-t-divider-subtle px-7 text-text-accent-light-mode-only system-xs-medium"
|
||||
onClick={handleAddNewCredential}
|
||||
>
|
||||
<RiAddLine className="mr-1 h-4 w-4" />
|
||||
|
|
|
|||
|
|
@ -244,6 +244,7 @@ const ModelLoadBalancingModal = ({
|
|||
<Modal
|
||||
isShow={Boolean(model) && open}
|
||||
onClose={onClose}
|
||||
wrapperClassName="z-[1002]"
|
||||
className="w-[640px] max-w-none px-8 pt-8"
|
||||
title={(
|
||||
<div className="pb-3 font-semibold">
|
||||
|
|
|
|||
|
|
@ -4700,9 +4700,6 @@
|
|||
"app/components/header/account-setting/data-source-page-new/configure.tsx": {
|
||||
"no-restricted-imports": {
|
||||
"count": 1
|
||||
},
|
||||
"tailwindcss/enforce-consistent-class-order": {
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"app/components/header/account-setting/data-source-page-new/hooks/use-marketplace-all-plugins.ts": {
|
||||
|
|
@ -4729,9 +4726,6 @@
|
|||
"app/components/header/account-setting/data-source-page-new/operator.tsx": {
|
||||
"no-restricted-imports": {
|
||||
"count": 2
|
||||
},
|
||||
"tailwindcss/enforce-consistent-class-order": {
|
||||
"count": 5
|
||||
}
|
||||
},
|
||||
"app/components/header/account-setting/data-source-page-new/types.ts": {
|
||||
|
|
@ -4758,28 +4752,10 @@
|
|||
}
|
||||
},
|
||||
"app/components/header/account-setting/members-page/invite-modal/index.tsx": {
|
||||
"no-restricted-imports": {
|
||||
"count": 2
|
||||
},
|
||||
"react/set-state-in-effect": {
|
||||
"count": 3
|
||||
}
|
||||
},
|
||||
"app/components/header/account-setting/members-page/invite-modal/role-selector.tsx": {
|
||||
"no-restricted-imports": {
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"app/components/header/account-setting/members-page/invited-modal/index.tsx": {
|
||||
"no-restricted-imports": {
|
||||
"count": 2
|
||||
}
|
||||
},
|
||||
"app/components/header/account-setting/members-page/invited-modal/invitation-link.tsx": {
|
||||
"no-restricted-imports": {
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"app/components/header/account-setting/members-page/operation/index.tsx": {
|
||||
"no-restricted-imports": {
|
||||
"count": 2
|
||||
|
|
@ -4833,9 +4809,6 @@
|
|||
"app/components/header/account-setting/model-provider-page/model-auth/add-custom-model.tsx": {
|
||||
"no-restricted-imports": {
|
||||
"count": 2
|
||||
},
|
||||
"tailwindcss/enforce-consistent-class-order": {
|
||||
"count": 2
|
||||
}
|
||||
},
|
||||
"app/components/header/account-setting/model-provider-page/model-auth/authorized/authorized-item.tsx": {
|
||||
|
|
@ -4847,9 +4820,6 @@
|
|||
"no-restricted-imports": {
|
||||
"count": 3
|
||||
},
|
||||
"tailwindcss/enforce-consistent-class-order": {
|
||||
"count": 2
|
||||
},
|
||||
"ts/no-explicit-any": {
|
||||
"count": 2
|
||||
}
|
||||
|
|
@ -4867,9 +4837,6 @@
|
|||
"app/components/header/account-setting/model-provider-page/model-auth/credential-selector.tsx": {
|
||||
"no-restricted-imports": {
|
||||
"count": 1
|
||||
},
|
||||
"tailwindcss/enforce-consistent-class-order": {
|
||||
"count": 4
|
||||
}
|
||||
},
|
||||
"app/components/header/account-setting/model-provider-page/model-auth/hooks/use-auth.ts": {
|
||||
|
|
|
|||
Loading…
Reference in New Issue