Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions api/controllers/console/app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ def put(self, app_model):
parser.add_argument("icon", type=str, location="json")
parser.add_argument("icon_background", type=str, location="json")
parser.add_argument("use_icon_as_answer_icon", type=bool, location="json")
parser.add_argument("max_active_requests", type=int, location="json")
args = parser.parse_args()

app_service = AppService()
Expand Down
1 change: 1 addition & 0 deletions api/fields/app_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@
"site": fields.Nested(site_fields),
"api_base_url": fields.String,
"use_icon_as_answer_icon": fields.Boolean,
"max_active_requests": fields.Integer,
"created_by": fields.String,
"created_at": TimestampField,
"updated_by": fields.String,
Expand Down
1 change: 1 addition & 0 deletions api/services/app_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ def update_app(self, app: App, args: dict) -> App:
app.icon = args.get("icon")
app.icon_background = args.get("icon_background")
app.use_icon_as_answer_icon = args.get("use_icon_as_answer_icon", False)
app.max_active_requests = args.get("max_active_requests")
app.updated_by = current_user.id
app.updated_at = datetime.now(UTC).replace(tzinfo=None)
db.session.commit()
Expand Down
3 changes: 3 additions & 0 deletions web/app/(commonLayout)/apps/AppCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
catch (e: any) {
notify({
type: 'error',
message: `${t('app.appDeleteFailed')}${'message' in e ? `: ${e.message}` : ''}`,

Check warning on line 78 in web/app/(commonLayout)/apps/AppCard.tsx

View workflow job for this annotation

GitHub Actions / Web Style

Refactor this code to not use nested template literals
})
}
setShowConfirmDelete(false)
Expand All @@ -88,6 +88,7 @@
icon_background,
description,
use_icon_as_answer_icon,
max_active_requests,
}) => {
try {
await updateAppInfo({
Expand All @@ -98,6 +99,7 @@
icon_background,
description,
use_icon_as_answer_icon,
max_active_requests,
})
setShowEditModal(false)
notify({
Expand Down Expand Up @@ -432,6 +434,7 @@
appDescription={app.description}
appMode={app.mode}
appUseIconAsAnswerIcon={app.use_icon_as_answer_icon}
max_active_requests={app.max_active_requests ?? null}
show={showEditModal}
onConfirm={onEdit}
onHide={() => setShowEditModal(false)}
Expand Down
3 changes: 3 additions & 0 deletions web/app/components/app-sidebar/app-info.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
icon_background,
description,
use_icon_as_answer_icon,
max_active_requests,
}) => {
if (!appDetail)
return
Expand All @@ -83,6 +84,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
icon_background,
description,
use_icon_as_answer_icon,
max_active_requests,
})
setShowEditModal(false)
notify({
Expand Down Expand Up @@ -352,6 +354,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
appDescription={appDetail.description}
appMode={appDetail.mode}
appUseIconAsAnswerIcon={appDetail.use_icon_as_answer_icon}
max_active_requests={appDetail.max_active_requests ?? null}
show={showEditModal}
onConfirm={onEdit}
onHide={() => setShowEditModal(false)}
Expand Down
34 changes: 31 additions & 3 deletions web/app/components/explore/create-app-modal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@ export type CreateAppModalProps = {
appIconUrl?: string | null
appMode?: string
appUseIconAsAnswerIcon?: boolean
max_active_requests: number | null
onConfirm: (info: {
name: string
icon_type: AppIconType
icon: string
icon_background?: string
description: string
use_icon_as_answer_icon?: boolean
max_active_requests?: number | null
}) => Promise<void>
confirmDisabled?: boolean
onHide: () => void
Expand All @@ -50,6 +52,7 @@ const CreateAppModal = ({
appDescription,
appMode,
appUseIconAsAnswerIcon,
max_active_requests,
onConfirm,
confirmDisabled,
onHide,
Expand All @@ -66,6 +69,10 @@ const CreateAppModal = ({
const [description, setDescription] = useState(appDescription || '')
const [useIconAsAnswerIcon, setUseIconAsAnswerIcon] = useState(appUseIconAsAnswerIcon || false)

const [maxActiveRequestsInput, setMaxActiveRequestsInput] = useState(
max_active_requests !== null && max_active_requests !== undefined ? String(max_active_requests) : '',
)

const { plan, enableBilling } = useProviderContext()
const isAppsFull = (enableBilling && plan.usage.buildApps >= plan.total.buildApps)

Expand All @@ -74,16 +81,21 @@ const CreateAppModal = ({
Toast.notify({ type: 'error', message: t('explore.appCustomize.nameRequired') })
return
}
onConfirm({
const isValid = maxActiveRequestsInput.trim() !== '' && !isNaN(Number(maxActiveRequestsInput))
const payload: any = {
name,
icon_type: appIcon.type,
icon: appIcon.type === 'emoji' ? appIcon.icon : appIcon.fileId,
icon_background: appIcon.type === 'emoji' ? appIcon.background! : undefined,
description,
use_icon_as_answer_icon: useIconAsAnswerIcon,
})
}
if (isValid)
payload.max_active_requests = Number(maxActiveRequestsInput)

onConfirm(payload)
onHide()
}, [name, appIcon, description, useIconAsAnswerIcon, onConfirm, onHide, t])
}, [name, appIcon, description, useIconAsAnswerIcon, onConfirm, onHide, t, maxActiveRequestsInput])

const { run: handleSubmit } = useDebounceFn(submit, { wait: 300 })

Expand Down Expand Up @@ -158,6 +170,22 @@ const CreateAppModal = ({
<p className='body-xs-regular text-text-tertiary'>{t('app.answerIcon.descriptionInExplore')}</p>
</div>
)}
{isEditModal && (
<div className='pt-2'>
<div className='mb-2 mt-2 text-sm font-medium leading-[20px] text-text-primary'>{t('app.maxActiveRequests')}</div>
<Input
type='number'
min={1}
placeholder={t('app.maxActiveRequestsPlaceholder')}
value={maxActiveRequestsInput}
onChange={(e) => {
setMaxActiveRequestsInput(e.target.value)
}}
className='h-10 w-full'
/>
<p className='body-xs-regular mb-0 mt-2 text-text-tertiary'>{t('app.maxActiveRequestsTip')}</p>
</div>
)}
{!isEditModal && isAppsFull && <AppsFull className='mt-4' loc='app-explore-create' />}
</div>
<div className='flex flex-row-reverse'>
Expand Down
3 changes: 3 additions & 0 deletions web/i18n/en-US/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,9 @@ const translation = {
notSetDesc: 'Currently nobody can access the web app. Please set permissions.',
},
noAccessPermission: 'No permission to access web app',
maxActiveRequests: 'Max concurrent requests',
maxActiveRequestsPlaceholder: 'Enter 0 for unlimited',
maxActiveRequestsTip: 'Maximum number of concurrent active requests per app (0 for unlimited)',
}

export default translation
3 changes: 3 additions & 0 deletions web/i18n/zh-Hans/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,9 @@ const translation = {
notSetDesc: '当前任何人都无法访问 Web 应用。请设置访问权限。',
},
noAccessPermission: '没有权限访问 web 应用',
maxActiveRequests: '最大活跃请求数',
maxActiveRequestsPlaceholder: '0 表示不限制',
maxActiveRequestsTip: '当前应用的最大活跃请求数(0 表示不限制)',
}

export default translation
5 changes: 3 additions & 2 deletions web/service/apps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ export const createApp: Fetcher<AppDetailResponse, { name: string; icon_type?: A
return post<AppDetailResponse>('apps', { body: { name, icon_type, icon, icon_background, mode, description, model_config: config } })
}

export const updateAppInfo: Fetcher<AppDetailResponse, { appID: string; name: string; icon_type: AppIconType; icon: string; icon_background?: string; description: string; use_icon_as_answer_icon?: boolean }> = ({ appID, name, icon_type, icon, icon_background, description, use_icon_as_answer_icon }) => {
return put<AppDetailResponse>(`apps/${appID}`, { body: { name, icon_type, icon, icon_background, description, use_icon_as_answer_icon } })
export const updateAppInfo: Fetcher<AppDetailResponse, { appID: string; name: string; icon_type: AppIconType; icon: string; icon_background?: string; description: string; use_icon_as_answer_icon?: boolean; max_active_requests?: number | null }> = ({ appID, name, icon_type, icon, icon_background, description, use_icon_as_answer_icon, max_active_requests }) => {
const body = { name, icon_type, icon, icon_background, description, use_icon_as_answer_icon, max_active_requests }
return put<AppDetailResponse>(`apps/${appID}`, { body })
}

export const copyApp: Fetcher<AppDetailResponse, { appID: string; name: string; icon_type: AppIconType; icon: string; icon_background?: string | null; mode: AppMode; description?: string }> = ({ appID, name, icon_type, icon, icon_background, mode, description }) => {
Expand Down
1 change: 1 addition & 0 deletions web/types/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ export type App = {
}
/** access control */
access_mode: AccessMode
max_active_requests?: number | null
}

export type AppSSO = {
Expand Down
Loading