mirror of
https://github.com/langgenius/dify.git
synced 2026-05-05 18:08:07 +08:00
feat: new editor user permission profile (#4435)
Co-authored-by: crazywoola <100913391+crazywoola@users.noreply.github.com> Co-authored-by: crazywoola <427733928@qq.com>
This commit is contained in:
@ -32,7 +32,7 @@ const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
|
||||
const pathname = usePathname()
|
||||
const media = useBreakpoints()
|
||||
const isMobile = media === MediaType.mobile
|
||||
const { isCurrentWorkspaceManager } = useAppContext()
|
||||
const { isCurrentWorkspaceManager, isCurrentWorkspaceEditor } = useAppContext()
|
||||
const { appDetail, setAppDetail, setAppSiderbarExpand } = useStore(useShallow(state => ({
|
||||
appDetail: state.appDetail,
|
||||
setAppDetail: state.setAppDetail,
|
||||
@ -45,9 +45,9 @@ const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
|
||||
selectedIcon: NavIcon
|
||||
}>>([])
|
||||
|
||||
const getNavigations = useCallback((appId: string, isCurrentWorkspaceManager: boolean, mode: string) => {
|
||||
const getNavigations = useCallback((appId: string, isCurrentWorkspaceManager: boolean, isCurrentWorkspaceEditor: boolean, mode: string) => {
|
||||
const navs = [
|
||||
...(isCurrentWorkspaceManager
|
||||
...(isCurrentWorkspaceEditor
|
||||
? [{
|
||||
name: t('common.appMenus.promptEng'),
|
||||
href: `/app/${appId}/${(mode === 'workflow' || mode === 'advanced-chat') ? 'workflow' : 'configuration'}`,
|
||||
@ -62,14 +62,17 @@ const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
|
||||
icon: TerminalSquare,
|
||||
selectedIcon: TerminalSquareSolid,
|
||||
},
|
||||
{
|
||||
name: mode !== 'workflow'
|
||||
? t('common.appMenus.logAndAnn')
|
||||
: t('common.appMenus.logs'),
|
||||
href: `/app/${appId}/logs`,
|
||||
icon: FileHeart02,
|
||||
selectedIcon: FileHeart02Solid,
|
||||
},
|
||||
...(isCurrentWorkspaceManager
|
||||
? [{
|
||||
name: mode !== 'workflow'
|
||||
? t('common.appMenus.logAndAnn')
|
||||
: t('common.appMenus.logs'),
|
||||
href: `/app/${appId}/logs`,
|
||||
icon: FileHeart02,
|
||||
selectedIcon: FileHeart02Solid,
|
||||
}]
|
||||
: []
|
||||
),
|
||||
{
|
||||
name: t('common.appMenus.overview'),
|
||||
href: `/app/${appId}/overview`,
|
||||
@ -104,10 +107,10 @@ const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
|
||||
}
|
||||
else {
|
||||
setAppDetail(res)
|
||||
setNavigation(getNavigations(appId, isCurrentWorkspaceManager, res.mode))
|
||||
setNavigation(getNavigations(appId, isCurrentWorkspaceManager, isCurrentWorkspaceEditor, res.mode))
|
||||
}
|
||||
})
|
||||
}, [appId, isCurrentWorkspaceManager])
|
||||
}, [appId, isCurrentWorkspaceManager, isCurrentWorkspaceEditor])
|
||||
|
||||
useUnmount(() => {
|
||||
setAppDetail()
|
||||
|
||||
@ -37,7 +37,7 @@ export type AppCardProps = {
|
||||
const AppCard = ({ app, onRefresh }: AppCardProps) => {
|
||||
const { t } = useTranslation()
|
||||
const { notify } = useContext(ToastContext)
|
||||
const { isCurrentWorkspaceManager } = useAppContext()
|
||||
const { isCurrentWorkspaceEditor } = useAppContext()
|
||||
const { onPlanInfoChanged } = useProviderContext()
|
||||
const { push } = useRouter()
|
||||
|
||||
@ -116,7 +116,7 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => {
|
||||
onRefresh()
|
||||
mutateApps()
|
||||
onPlanInfoChanged()
|
||||
getRedirection(isCurrentWorkspaceManager, newApp, push)
|
||||
getRedirection(isCurrentWorkspaceEditor, newApp, push)
|
||||
}
|
||||
catch (e) {
|
||||
notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
|
||||
@ -224,7 +224,7 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => {
|
||||
<div
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
getRedirection(isCurrentWorkspaceManager, app, push)
|
||||
getRedirection(isCurrentWorkspaceEditor, app, push)
|
||||
}}
|
||||
className='group flex col-span-1 bg-white border-2 border-solid border-transparent rounded-xl shadow-sm min-h-[160px] flex flex-col transition-all duration-200 ease-in-out cursor-pointer hover:shadow-lg'
|
||||
>
|
||||
@ -298,7 +298,7 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{isCurrentWorkspaceManager && (
|
||||
{isCurrentWorkspaceEditor && (
|
||||
<>
|
||||
<div className='!hidden group-hover:!flex shrink-0 mx-1 w-[1px] h-[14px] bg-gray-200'/>
|
||||
<div className='!hidden group-hover:!flex shrink-0'>
|
||||
|
||||
@ -50,7 +50,7 @@ const getKey = (
|
||||
|
||||
const Apps = () => {
|
||||
const { t } = useTranslation()
|
||||
const { isCurrentWorkspaceManager } = useAppContext()
|
||||
const { isCurrentWorkspaceEditor } = useAppContext()
|
||||
const showTagManagementModal = useTagStore(s => s.showTagManagementModal)
|
||||
const [activeTab, setActiveTab] = useTabSearchParams({
|
||||
defaultTab: 'all',
|
||||
@ -130,7 +130,7 @@ const Apps = () => {
|
||||
</div>
|
||||
</div>
|
||||
<nav className='grid content-start grid-cols-1 gap-4 px-12 pt-2 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 grow shrink-0'>
|
||||
{isCurrentWorkspaceManager
|
||||
{isCurrentWorkspaceEditor
|
||||
&& <NewAppCard onSuccess={mutate} />}
|
||||
{data?.map(({ data: apps }: any) => apps.map((app: any) => (
|
||||
<AppCard key={app.id} app={app} onRefresh={mutate} />
|
||||
|
||||
@ -44,7 +44,7 @@ const Datasets = ({
|
||||
tags,
|
||||
keywords,
|
||||
}: Props) => {
|
||||
const { isCurrentWorkspaceManager } = useAppContext()
|
||||
const { isCurrentWorkspaceEditor } = useAppContext()
|
||||
const { data, isLoading, setSize, mutate } = useSWRInfinite(
|
||||
(pageIndex: number, previousPageData: DataSetListResponse) => getKey(pageIndex, previousPageData, tags, keywords),
|
||||
fetchDatasets,
|
||||
@ -76,7 +76,7 @@ const Datasets = ({
|
||||
|
||||
return (
|
||||
<nav className='grid content-start grid-cols-1 gap-4 px-12 pt-2 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 grow shrink-0'>
|
||||
{ isCurrentWorkspaceManager && <NewDatasetCard ref={anchorRef} /> }
|
||||
{ isCurrentWorkspaceEditor && <NewDatasetCard ref={anchorRef} /> }
|
||||
{data?.map(({ data: datasets }) => datasets.map(dataset => (
|
||||
<DatasetCard key={dataset.id} dataset={dataset} onSuccess={mutate} />),
|
||||
))}
|
||||
|
||||
@ -44,7 +44,7 @@ const CreateAppModal = ({ show, onSuccess, onClose }: CreateAppDialogProps) => {
|
||||
|
||||
const { plan, enableBilling } = useProviderContext()
|
||||
const isAppsFull = (enableBilling && plan.usage.buildApps >= plan.total.buildApps)
|
||||
const { isCurrentWorkspaceManager } = useAppContext()
|
||||
const { isCurrentWorkspaceEditor } = useAppContext()
|
||||
|
||||
const isCreatingRef = useRef(false)
|
||||
const onCreate: MouseEventHandler = useCallback(async () => {
|
||||
@ -72,13 +72,13 @@ const CreateAppModal = ({ show, onSuccess, onClose }: CreateAppDialogProps) => {
|
||||
onClose()
|
||||
mutateApps()
|
||||
localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
|
||||
getRedirection(isCurrentWorkspaceManager, app, push)
|
||||
getRedirection(isCurrentWorkspaceEditor, app, push)
|
||||
}
|
||||
catch (e) {
|
||||
notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
|
||||
}
|
||||
isCreatingRef.current = false
|
||||
}, [name, notify, t, appMode, emoji.icon, emoji.icon_background, description, onSuccess, onClose, mutateApps, push, isCurrentWorkspaceManager])
|
||||
}, [name, notify, t, appMode, emoji.icon, emoji.icon_background, description, onSuccess, onClose, mutateApps, push, isCurrentWorkspaceEditor])
|
||||
|
||||
return (
|
||||
<Modal
|
||||
|
||||
@ -47,7 +47,7 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose }: CreateFromDSLModalProp
|
||||
setFileContent('')
|
||||
}
|
||||
|
||||
const { isCurrentWorkspaceManager } = useAppContext()
|
||||
const { isCurrentWorkspaceEditor } = useAppContext()
|
||||
const { plan, enableBilling } = useProviderContext()
|
||||
const isAppsFull = (enableBilling && plan.usage.buildApps >= plan.total.buildApps)
|
||||
|
||||
@ -68,7 +68,7 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose }: CreateFromDSLModalProp
|
||||
onClose()
|
||||
notify({ type: 'success', message: t('app.newApp.appCreated') })
|
||||
localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
|
||||
getRedirection(isCurrentWorkspaceManager, app, push)
|
||||
getRedirection(isCurrentWorkspaceEditor, app, push)
|
||||
}
|
||||
catch (e) {
|
||||
notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
|
||||
|
||||
@ -53,7 +53,7 @@ function AppCard({
|
||||
}: IAppCardProps) {
|
||||
const router = useRouter()
|
||||
const pathname = usePathname()
|
||||
const { currentWorkspace, isCurrentWorkspaceManager } = useAppContext()
|
||||
const { currentWorkspace, isCurrentWorkspaceManager, isCurrentWorkspaceEditor } = useAppContext()
|
||||
const [showSettingsModal, setShowSettingsModal] = useState(false)
|
||||
const [showEmbedded, setShowEmbedded] = useState(false)
|
||||
const [showCustomizeModal, setShowCustomizeModal] = useState(false)
|
||||
@ -74,16 +74,17 @@ function AppCard({
|
||||
if (appInfo.mode !== 'completion' && appInfo.mode !== 'workflow')
|
||||
operationsMap.webapp.push({ opName: t('appOverview.overview.appInfo.embedded.entry'), opIcon: EmbedIcon })
|
||||
|
||||
if (isCurrentWorkspaceManager)
|
||||
if (isCurrentWorkspaceEditor)
|
||||
operationsMap.webapp.push({ opName: t('appOverview.overview.appInfo.settings.entry'), opIcon: Cog8ToothIcon })
|
||||
|
||||
return operationsMap
|
||||
}, [isCurrentWorkspaceManager, appInfo, t])
|
||||
}, [isCurrentWorkspaceEditor, appInfo, t])
|
||||
|
||||
const isApp = cardType === 'webapp'
|
||||
const basicName = isApp
|
||||
? appInfo?.site?.title
|
||||
: t('appOverview.overview.apiInfo.title')
|
||||
const toggleDisabled = isApp ? !isCurrentWorkspaceEditor : !isCurrentWorkspaceManager
|
||||
const runningStatus = isApp ? appInfo.enable_site : appInfo.enable_api
|
||||
const { app_base_url, access_token } = appInfo.site ?? {}
|
||||
const appMode = (appInfo.mode !== 'completion' && appInfo.mode !== 'workflow') ? 'chat' : appInfo.mode
|
||||
@ -154,7 +155,7 @@ function AppCard({
|
||||
? t('appOverview.overview.status.running')
|
||||
: t('appOverview.overview.status.disable')}
|
||||
</Tag>
|
||||
<Switch defaultValue={runningStatus} onChange={onChangeStatus} disabled={currentWorkspace?.role === 'normal'} />
|
||||
<Switch defaultValue={runningStatus} onChange={onChangeStatus} disabled={toggleDisabled} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col justify-center py-2">
|
||||
|
||||
@ -37,7 +37,7 @@ const SwitchAppModal = ({ show, appDetail, inAppDetail = false, onSuccess, onClo
|
||||
const { notify } = useContext(ToastContext)
|
||||
const setAppDetail = useAppStore(s => s.setAppDetail)
|
||||
|
||||
const { isCurrentWorkspaceManager } = useAppContext()
|
||||
const { isCurrentWorkspaceEditor } = useAppContext()
|
||||
const { plan, enableBilling } = useProviderContext()
|
||||
const isAppsFull = (enableBilling && plan.usage.buildApps >= plan.total.buildApps)
|
||||
|
||||
@ -66,7 +66,7 @@ const SwitchAppModal = ({ show, appDetail, inAppDetail = false, onSuccess, onClo
|
||||
await deleteApp(appDetail.id)
|
||||
localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
|
||||
getRedirection(
|
||||
isCurrentWorkspaceManager,
|
||||
isCurrentWorkspaceEditor,
|
||||
{
|
||||
id: newAppID,
|
||||
mode: appDetail.mode === 'completion' ? 'workflow' : 'advanced-chat',
|
||||
|
||||
@ -143,7 +143,7 @@ const SecretKeyModal = ({
|
||||
)
|
||||
}
|
||||
<div className='flex'>
|
||||
<Button type='default' className={`flex flex-shrink-0 mt-4 ${s.autoWidth}`} onClick={onCreate} disabled={ !currentWorkspace || currentWorkspace.role === 'normal'}>
|
||||
<Button type='default' className={`flex flex-shrink-0 mt-4 ${s.autoWidth}`} onClick={onCreate} disabled={ !currentWorkspace || !isCurrentWorkspaceManager}>
|
||||
<PlusIcon className='flex flex-shrink-0 w-4 h-4' />
|
||||
<div className='text-xs font-medium text-gray-800'>{t('appApi.apiKeyModal.createNewSecretKey')}</div>
|
||||
</Button>
|
||||
|
||||
@ -38,7 +38,7 @@ const Apps = ({
|
||||
onSuccess,
|
||||
}: AppsProps) => {
|
||||
const { t } = useTranslation()
|
||||
const { isCurrentWorkspaceManager } = useAppContext()
|
||||
const { isCurrentWorkspaceEditor } = useAppContext()
|
||||
const { push } = useRouter()
|
||||
const { hasEditPermission } = useContext(ExploreContext)
|
||||
const allCategoriesEn = t('explore.apps.allCategories', { lng: 'en' })
|
||||
@ -116,7 +116,7 @@ const Apps = ({
|
||||
if (onSuccess)
|
||||
onSuccess()
|
||||
localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
|
||||
getRedirection(isCurrentWorkspaceManager, app, push)
|
||||
getRedirection(isCurrentWorkspaceEditor, app, push)
|
||||
}
|
||||
catch (e) {
|
||||
Toast.notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
|
||||
|
||||
@ -28,6 +28,7 @@ const MembersPage = () => {
|
||||
const RoleMap = {
|
||||
owner: t('common.members.owner'),
|
||||
admin: t('common.members.admin'),
|
||||
editor: t('common.members.editor'),
|
||||
normal: t('common.members.normal'),
|
||||
}
|
||||
const { locale } = useContext(I18n)
|
||||
|
||||
@ -37,6 +37,10 @@ const InviteModal = ({
|
||||
name: 'normal',
|
||||
description: t('common.members.normalTip'),
|
||||
},
|
||||
{
|
||||
name: 'editor',
|
||||
description: t('common.members.editorTip'),
|
||||
},
|
||||
{
|
||||
name: 'admin',
|
||||
description: t('common.members.adminTip'),
|
||||
@ -120,7 +124,7 @@ const InviteModal = ({
|
||||
<div className='flex flex-row'>
|
||||
<span
|
||||
className={cn(
|
||||
'text-indigo-600 w-8',
|
||||
'text-indigo-600 mr-2',
|
||||
'flex items-center',
|
||||
)}
|
||||
>
|
||||
@ -130,7 +134,7 @@ const InviteModal = ({
|
||||
<span className={`${selected ? 'font-medium' : 'font-normal'} capitalize block truncate`}>
|
||||
{t(`common.members.${role.name}`)}
|
||||
</span>
|
||||
<span className={`${selected ? 'font-medium' : 'font-normal'} capitalize block truncate`}>
|
||||
<span className={`${selected ? 'font-medium' : 'font-normal'} capitalize block text-gray-500`}>
|
||||
{role.description}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@ -36,6 +36,7 @@ const Operation = ({
|
||||
const RoleMap = {
|
||||
owner: t('common.members.owner'),
|
||||
admin: t('common.members.admin'),
|
||||
editor: t('common.members.editor'),
|
||||
normal: t('common.members.normal'),
|
||||
}
|
||||
const { notify } = useContext(ToastContext)
|
||||
@ -98,7 +99,7 @@ const Operation = ({
|
||||
>
|
||||
<div className="px-1 py-1">
|
||||
{
|
||||
['admin', 'normal'].map(role => (
|
||||
['admin', 'editor', 'normal'].map(role => (
|
||||
<Menu.Item key={role}>
|
||||
<div className={itemClassName} onClick={() => handleUpdateMemberRole(role)}>
|
||||
{
|
||||
|
||||
@ -47,6 +47,7 @@ import {
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
import { useToastContext } from '@/app/components/base/toast'
|
||||
import ConfirmCommon from '@/app/components/base/confirm/common'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
|
||||
type ModelModalProps = {
|
||||
provider: ModelProvider
|
||||
@ -74,7 +75,8 @@ const ModelModal: FC<ModelModalProps> = ({
|
||||
providerFormSchemaPredefined && provider.custom_configuration.status === CustomConfigurationStatusEnum.active,
|
||||
currentCustomConfigurationModelFixedFields,
|
||||
)
|
||||
const isEditMode = !!formSchemasValue
|
||||
const { isCurrentWorkspaceManager } = useAppContext()
|
||||
const isEditMode = !!formSchemasValue && isCurrentWorkspaceManager
|
||||
const { t } = useTranslation()
|
||||
const { notify } = useToastContext()
|
||||
const language = useLanguage()
|
||||
@ -344,6 +346,7 @@ const ModelModal: FC<ModelModalProps> = ({
|
||||
|| filteredRequiredFormSchemas.some(item => value[item.variable] === undefined)
|
||||
|| (draftConfig?.enabled && (draftConfig?.configs.filter(config => config.enabled).length ?? 0) < 2)
|
||||
}
|
||||
|
||||
>
|
||||
{t('common.operation.save')}
|
||||
</Button>
|
||||
|
||||
@ -23,6 +23,7 @@ import Button from '@/app/components/base/button'
|
||||
import { useProviderContext } from '@/context/provider-context'
|
||||
import { updateDefaultModel } from '@/service/common'
|
||||
import { useToastContext } from '@/app/components/base/toast'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
|
||||
type SystemModelSelectorProps = {
|
||||
textGenerationDefaultModel: DefaultModelResponse | undefined
|
||||
@ -40,6 +41,7 @@ const SystemModel: FC<SystemModelSelectorProps> = ({
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const { notify } = useToastContext()
|
||||
const { isCurrentWorkspaceManager } = useAppContext()
|
||||
const { textGenerationModelList } = useProviderContext()
|
||||
const updateModelList = useUpdateModelList()
|
||||
const { data: embeddingModelList } = useModelList(ModelTypeEnum.textEmbedding)
|
||||
@ -248,6 +250,7 @@ const SystemModel: FC<SystemModelSelectorProps> = ({
|
||||
type='primary'
|
||||
className='!h-8 !text-[13px]'
|
||||
onClick={handleSave}
|
||||
disabled={!isCurrentWorkspaceManager}
|
||||
>
|
||||
{t('common.operation.save')}
|
||||
</Button>
|
||||
|
||||
@ -39,7 +39,7 @@ const getKey = (
|
||||
const AppNav = () => {
|
||||
const { t } = useTranslation()
|
||||
const { appId } = useParams()
|
||||
const { isCurrentWorkspaceManager } = useAppContext()
|
||||
const { isCurrentWorkspaceEditor } = useAppContext()
|
||||
const appDetail = useAppStore(state => state.appDetail)
|
||||
const [showNewAppDialog, setShowNewAppDialog] = useState(false)
|
||||
const [showNewAppTemplateDialog, setShowNewAppTemplateDialog] = useState(false)
|
||||
@ -71,8 +71,8 @@ const AppNav = () => {
|
||||
if (appsData) {
|
||||
const appItems = flatten(appsData?.map(appData => appData.data))
|
||||
const navItems = appItems.map((app) => {
|
||||
const link = ((isCurrentWorkspaceManager, app) => {
|
||||
if (!isCurrentWorkspaceManager) {
|
||||
const link = ((isCurrentWorkspaceEditor, app) => {
|
||||
if (!isCurrentWorkspaceEditor) {
|
||||
return `/app/${app.id}/overview`
|
||||
}
|
||||
else {
|
||||
@ -81,7 +81,7 @@ const AppNav = () => {
|
||||
else
|
||||
return `/app/${app.id}/configuration`
|
||||
}
|
||||
})(isCurrentWorkspaceManager, app)
|
||||
})(isCurrentWorkspaceEditor, app)
|
||||
return {
|
||||
id: app.id,
|
||||
icon: app.icon,
|
||||
@ -93,7 +93,7 @@ const AppNav = () => {
|
||||
})
|
||||
setNavItems(navItems)
|
||||
}
|
||||
}, [appsData, isCurrentWorkspaceManager, setNavItems])
|
||||
}, [appsData, isCurrentWorkspaceEditor, setNavItems])
|
||||
|
||||
// update current app name
|
||||
useEffect(() => {
|
||||
|
||||
@ -17,7 +17,7 @@ type IAppSelectorProps = {
|
||||
|
||||
export default function AppSelector({ appItems, curApp }: IAppSelectorProps) {
|
||||
const router = useRouter()
|
||||
const { isCurrentWorkspaceManager } = useAppContext()
|
||||
const { isCurrentWorkspaceEditor } = useAppContext()
|
||||
const [showNewAppDialog, setShowNewAppDialog] = useState(false)
|
||||
const { t } = useTranslation()
|
||||
|
||||
@ -65,7 +65,7 @@ export default function AppSelector({ appItems, curApp }: IAppSelectorProps) {
|
||||
appItems.map((app: AppDetailResponse) => (
|
||||
<Menu.Item key={app.id}>
|
||||
<div className={itemClassName} onClick={() =>
|
||||
router.push(`/app/${app.id}/${isCurrentWorkspaceManager ? 'configuration' : 'overview'}`)
|
||||
router.push(`/app/${app.id}/${isCurrentWorkspaceEditor ? 'configuration' : 'overview'}`)
|
||||
}>
|
||||
<div className='relative w-6 h-6 mr-2 bg-[#D5F5F6] rounded-[6px]'>
|
||||
<AppIcon size='tiny' />
|
||||
@ -79,7 +79,7 @@ export default function AppSelector({ appItems, curApp }: IAppSelectorProps) {
|
||||
))
|
||||
}
|
||||
</div>)}
|
||||
{isCurrentWorkspaceManager && <Menu.Item>
|
||||
{isCurrentWorkspaceEditor && <Menu.Item>
|
||||
<div className='p-1' onClick={() => setShowNewAppDialog(true)}>
|
||||
<div
|
||||
className='flex items-center h-12 rounded-lg cursor-pointer hover:bg-gray-100'
|
||||
|
||||
@ -26,7 +26,7 @@ const navClassName = `
|
||||
`
|
||||
|
||||
const Header = () => {
|
||||
const { isCurrentWorkspaceManager } = useAppContext()
|
||||
const { isCurrentWorkspaceEditor } = useAppContext()
|
||||
|
||||
const selectedSegment = useSelectedLayoutSegment()
|
||||
const media = useBreakpoints()
|
||||
@ -74,7 +74,7 @@ const Header = () => {
|
||||
<div className='flex items-center'>
|
||||
<ExploreNav className={navClassName} />
|
||||
<AppNav />
|
||||
{isCurrentWorkspaceManager && <DatasetNav />}
|
||||
{isCurrentWorkspaceEditor && <DatasetNav />}
|
||||
<ToolsNav className={navClassName} />
|
||||
</div>
|
||||
)}
|
||||
@ -93,7 +93,7 @@ const Header = () => {
|
||||
<div className='w-full flex flex-col p-2 gap-y-1'>
|
||||
<ExploreNav className={navClassName} />
|
||||
<AppNav />
|
||||
{isCurrentWorkspaceManager && <DatasetNav />}
|
||||
{isCurrentWorkspaceEditor && <DatasetNav />}
|
||||
<ToolsNav className={navClassName} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -34,7 +34,7 @@ export type INavSelectorProps = {
|
||||
const NavSelector = ({ curNav, navs, createText, isApp, onCreate, onLoadmore }: INavSelectorProps) => {
|
||||
const { t } = useTranslation()
|
||||
const router = useRouter()
|
||||
const { isCurrentWorkspaceManager } = useAppContext()
|
||||
const { isCurrentWorkspaceEditor } = useAppContext()
|
||||
const setAppDetail = useAppStore(state => state.setAppDetail)
|
||||
|
||||
const handleScroll = useCallback(debounce((e) => {
|
||||
@ -122,7 +122,7 @@ const NavSelector = ({ curNav, navs, createText, isApp, onCreate, onLoadmore }:
|
||||
</div>
|
||||
</Menu.Button>
|
||||
)}
|
||||
{isApp && isCurrentWorkspaceManager && (
|
||||
{isApp && isCurrentWorkspaceEditor && (
|
||||
<Menu as="div" className="relative w-full h-full">
|
||||
{({ open }) => (
|
||||
<>
|
||||
|
||||
@ -11,6 +11,7 @@ import { ArrowUpRight } from '@/app/components/base/icons/src/vender/line/arrows
|
||||
import EditCustomToolModal from '@/app/components/tools/edit-custom-collection-modal'
|
||||
import { createCustomCollection } from '@/service/tools'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
|
||||
type Props = {
|
||||
onRefreshData: () => void
|
||||
@ -20,6 +21,7 @@ const Contribute = ({ onRefreshData }: Props) => {
|
||||
const { t } = useTranslation()
|
||||
const { locale } = useContext(I18n)
|
||||
const language = getLanguage(locale)
|
||||
const { isCurrentWorkspaceManager } = useAppContext()
|
||||
|
||||
const linkUrl = useMemo(() => {
|
||||
if (language.startsWith('zh_'))
|
||||
@ -40,23 +42,25 @@ const Contribute = ({ onRefreshData }: Props) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='flex flex-col col-span-1 bg-gray-200 border-[0.5px] border-black/5 rounded-xl min-h-[160px] transition-all duration-200 ease-in-out cursor-pointer hover:bg-gray-50 hover:shadow-lg'>
|
||||
<div className='group grow rounded-t-xl hover:bg-white' onClick={() => setIsShowEditCustomCollectionModal(true)}>
|
||||
<div className='shrink-0 flex items-center p-4 pb-3'>
|
||||
<div className='w-10 h-10 flex items-center justify-center border border-gray-200 bg-gray-100 rounded-lg group-hover:border-primary-100 group-hover:bg-primary-50'>
|
||||
<Plus className='w-4 h-4 text-gray-500 group-hover:text-primary-600'/>
|
||||
{isCurrentWorkspaceManager && (
|
||||
<div className='flex flex-col col-span-1 bg-gray-200 border-[0.5px] border-black/5 rounded-xl min-h-[160px] transition-all duration-200 ease-in-out cursor-pointer hover:bg-gray-50 hover:shadow-lg'>
|
||||
<div className='group grow rounded-t-xl hover:bg-white' onClick={() => setIsShowEditCustomCollectionModal(true)}>
|
||||
<div className='shrink-0 flex items-center p-4 pb-3'>
|
||||
<div className='w-10 h-10 flex items-center justify-center border border-gray-200 bg-gray-100 rounded-lg group-hover:border-primary-100 group-hover:bg-primary-50'>
|
||||
<Plus className='w-4 h-4 text-gray-500 group-hover:text-primary-600'/>
|
||||
</div>
|
||||
<div className='ml-3 text-sm font-semibold leading-5 text-gray-800 group-hover:text-primary-600'>{t('tools.createCustomTool')}</div>
|
||||
</div>
|
||||
<div className='ml-3 text-sm font-semibold leading-5 text-gray-800 group-hover:text-primary-600'>{t('tools.createCustomTool')}</div>
|
||||
</div>
|
||||
<div className='px-4 py-3 rounded-b-xl border-t-[0.5px] border-black/5 text-gray-500 hover:text-[#155EEF] hover:bg-white'>
|
||||
<a href={linkUrl} target='_blank' rel='noopener noreferrer' className='flex items-center space-x-1'>
|
||||
<BookOpen01 className='shrink-0 w-3 h-3' />
|
||||
<div className='grow leading-[18px] text-xs font-normal truncate' title={t('tools.customToolTip') || ''}>{t('tools.customToolTip')}</div>
|
||||
<ArrowUpRight className='shrink-0 w-3 h-3' />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className='px-4 py-3 rounded-b-xl border-t-[0.5px] border-black/5 text-gray-500 hover:text-[#155EEF] hover:bg-white'>
|
||||
<a href={linkUrl} target='_blank' rel='noopener noreferrer' className='flex items-center space-x-1'>
|
||||
<BookOpen01 className='shrink-0 w-3 h-3' />
|
||||
<div className='grow leading-[18px] text-xs font-normal truncate' title={t('tools.customToolTip') || ''}>{t('tools.customToolTip')}</div>
|
||||
<ArrowUpRight className='shrink-0 w-3 h-3' />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{isShowEditCollectionToolModal && (
|
||||
<EditCustomToolModal
|
||||
payload={null}
|
||||
|
||||
@ -33,6 +33,7 @@ import { useModalContext } from '@/context/modal-context'
|
||||
import { useProviderContext } from '@/context/provider-context'
|
||||
import { ConfigurationMethodEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
|
||||
type Props = {
|
||||
collection: Collection
|
||||
@ -51,6 +52,7 @@ const ProviderDetail = ({
|
||||
const isAuthed = collection.is_team_authorization
|
||||
const isBuiltIn = collection.type === CollectionType.builtIn
|
||||
const isModel = collection.type === CollectionType.model
|
||||
const { isCurrentWorkspaceManager } = useAppContext()
|
||||
|
||||
const [isDetailLoading, setIsDetailLoading] = useState(false)
|
||||
|
||||
@ -221,6 +223,7 @@ const ProviderDetail = ({
|
||||
if (collection.type === CollectionType.builtIn || collection.type === CollectionType.model)
|
||||
showSettingAuthModal()
|
||||
}}
|
||||
disabled={!isCurrentWorkspaceManager}
|
||||
>
|
||||
{isAuthed && <Indicator className='mr-2' color={'green'} />}
|
||||
<div className={cn('text-white leading-[18px] text-[13px] font-medium', isAuthed && '!text-gray-700')}>
|
||||
@ -251,6 +254,7 @@ const ProviderDetail = ({
|
||||
<Button
|
||||
className={cn('shrink-0 my-3 w-[183px] flex items-center bg-white')}
|
||||
onClick={() => setIsShowEditWorkflowToolModal(true)}
|
||||
disabled={!isCurrentWorkspaceManager}
|
||||
>
|
||||
<div className='leading-5 text-sm font-medium text-gray-700'>{t('tools.createTool.editAction')}</div>
|
||||
</Button>
|
||||
|
||||
@ -11,6 +11,7 @@ import { fetchBuiltInToolCredential, fetchBuiltInToolCredentialSchema } from '@/
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import Form from '@/app/components/header/account-setting/model-provider-page/model-modal/Form'
|
||||
import { LinkExternal02 } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
|
||||
type Props = {
|
||||
collection: Collection
|
||||
@ -29,6 +30,7 @@ const ConfigCredential: FC<Props> = ({
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const [credentialSchema, setCredentialSchema] = useState<any>(null)
|
||||
const { isCurrentWorkspaceManager } = useAppContext()
|
||||
const { name: collectionName } = collection
|
||||
const [tempCredential, setTempCredential] = React.useState<any>({})
|
||||
useEffect(() => {
|
||||
|
||||
@ -13,6 +13,7 @@ import Toast from '@/app/components/base/toast'
|
||||
import { createWorkflowToolProvider, fetchWorkflowToolDetailByAppID, saveWorkflowToolProvider } from '@/service/tools'
|
||||
import type { Emoji, WorkflowToolProviderParameter, WorkflowToolProviderRequest, WorkflowToolProviderResponse } from '@/app/components/tools/types'
|
||||
import type { InputVar } from '@/app/components/workflow/types'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
|
||||
type Props = {
|
||||
disabled: boolean
|
||||
@ -44,6 +45,7 @@ const WorkflowToolConfigureButton = ({
|
||||
const [showModal, setShowModal] = useState(false)
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [detail, setDetail] = useState<WorkflowToolProviderResponse>()
|
||||
const { isCurrentWorkspaceManager } = useAppContext()
|
||||
|
||||
const outdated = useMemo(() => {
|
||||
if (!detail)
|
||||
@ -175,22 +177,33 @@ const WorkflowToolConfigureButton = ({
|
||||
disabled ? 'shadow-xs opacity-30 cursor-not-allowed' : 'cursor-pointer',
|
||||
!published && 'hover:bg-primary-50',
|
||||
)}>
|
||||
<div
|
||||
className='flex justify-start items-center gap-2 px-2.5 py-2'
|
||||
onClick={() => !published && setShowModal(true)}
|
||||
>
|
||||
<Tools className={cn('relative w-4 h-4', !published && 'group-hover:text-primary-600')}/>
|
||||
<div title={t('workflow.common.workflowAsTool') || ''} className={cn('grow shrink basis-0 text-[13px] font-medium leading-[18px] truncate', !published && 'group-hover:text-primary-600')}>{t('workflow.common.workflowAsTool')}</div>
|
||||
{!published && (
|
||||
<span className='shrink-0 px-1 border border-black/8 rounded-[5px] bg-white text-[10px] font-medium leading-[18px] text-gray-500'>{t('workflow.common.configureRequired').toLocaleUpperCase()}</span>
|
||||
{isCurrentWorkspaceManager
|
||||
? (
|
||||
<div
|
||||
className='flex justify-start items-center gap-2 px-2.5 py-2'
|
||||
onClick={() => !published && setShowModal(true)}
|
||||
>
|
||||
<Tools className={cn('relative w-4 h-4', !published && 'group-hover:text-primary-600')} />
|
||||
<div title={t('workflow.common.workflowAsTool') || ''} className={cn('grow shrink basis-0 text-[13px] font-medium leading-[18px] truncate', !published && 'group-hover:text-primary-600')}>{t('workflow.common.workflowAsTool')}</div>
|
||||
{!published && (
|
||||
<span className='shrink-0 px-1 border border-black/8 rounded-[5px] bg-white text-[10px] font-medium leading-[18px] text-gray-500'>{t('workflow.common.configureRequired').toLocaleUpperCase()}</span>
|
||||
)}
|
||||
</div>)
|
||||
: (
|
||||
<div
|
||||
className='flex justify-start items-center gap-2 px-2.5 py-2'
|
||||
>
|
||||
<Tools className='w-4 h-4 text-gray-500' />
|
||||
<div title={t('workflow.common.workflowAsTool') || ''} className='grow shrink basis-0 text-[13px] font-medium leading-[18px] truncate text-gray-500'>{t('workflow.common.workflowAsTool')}</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{published && (
|
||||
<div className='px-2.5 py-2 border-t-[0.5px] border-black/5'>
|
||||
<div className='flex justify-between'>
|
||||
<Button
|
||||
className='px-2 w-[140px] py-0 h-6 shadow-xs rounded-md text-xs font-medium text-gray-700 border-[0.5px] bg-white border-gray-200'
|
||||
onClick={() => setShowModal(true)}
|
||||
disabled={!isCurrentWorkspaceManager}
|
||||
>
|
||||
{t('workflow.common.configure')}
|
||||
{outdated && <Indicator className='ml-1' color={'yellow'} />}
|
||||
@ -208,7 +221,7 @@ const WorkflowToolConfigureButton = ({
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{published && isLoading && <div className='pt-2'><Loading type='app'/></div>}
|
||||
{published && isLoading && <div className='pt-2'><Loading type='app' /></div>}
|
||||
</div>
|
||||
{showModal && (
|
||||
<WorkflowToolModal
|
||||
|
||||
Reference in New Issue
Block a user