merge main
commit
11977596c9
@ -0,0 +1,30 @@
|
||||
from flask_restful import Resource, marshal_with
|
||||
from werkzeug.exceptions import Forbidden
|
||||
|
||||
from controllers.common import fields
|
||||
from controllers.service_api import api
|
||||
from controllers.service_api.wraps import validate_app_token
|
||||
from extensions.ext_database import db
|
||||
from models.account import TenantStatus
|
||||
from models.model import App, Site
|
||||
|
||||
|
||||
class AppSiteApi(Resource):
|
||||
"""Resource for app sites."""
|
||||
|
||||
@validate_app_token
|
||||
@marshal_with(fields.site_fields)
|
||||
def get(self, app_model: App):
|
||||
"""Retrieve app site info."""
|
||||
site = db.session.query(Site).filter(Site.app_id == app_model.id).first()
|
||||
|
||||
if not site:
|
||||
raise Forbidden()
|
||||
|
||||
if app_model.tenant.status == TenantStatus.ARCHIVE:
|
||||
raise Forbidden()
|
||||
|
||||
return site
|
||||
|
||||
|
||||
api.add_resource(AppSiteApi, "/site")
|
||||
@ -0,0 +1,33 @@
|
||||
"""add index for workflow_conversation_variables.conversation_id
|
||||
|
||||
Revision ID: d28f2004b072
|
||||
Revises: 6a9f914f656c
|
||||
Create Date: 2025-05-14 14:03:36.713828
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import models as models
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'd28f2004b072'
|
||||
down_revision = '6a9f914f656c'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('workflow_conversation_variables', schema=None) as batch_op:
|
||||
batch_op.create_index(batch_op.f('workflow_conversation_variables_conversation_id_idx'), ['conversation_id'], unique=False)
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('workflow_conversation_variables', schema=None) as batch_op:
|
||||
batch_op.drop_index(batch_op.f('workflow_conversation_variables_conversation_id_idx'))
|
||||
|
||||
# ### end Alembic commands ###
|
||||
@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -x
|
||||
|
||||
SCRIPT_DIR="$(dirname "$(realpath "$0")")"
|
||||
cd "$SCRIPT_DIR/.."
|
||||
|
||||
|
||||
uv --directory api run \
|
||||
flask run --host 0.0.0.0 --port=5001 --debug
|
||||
@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -x
|
||||
|
||||
SCRIPT_DIR="$(dirname "$(realpath "$0")")"
|
||||
cd "$SCRIPT_DIR/.."
|
||||
|
||||
|
||||
uv --directory api run \
|
||||
celery -A app.celery worker \
|
||||
-P gevent -c 1 --loglevel INFO -Q dataset,generation,mail,ops_trace,app_deletion
|
||||
@ -0,0 +1,9 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="Icon L">
|
||||
<g id="Vector">
|
||||
<path d="M2.66602 11.3333H0.666016L3.33268 8.66667L5.99935 11.3333H3.99935L3.99935 14H2.66602L2.66602 11.3333Z" fill="#354052"/>
|
||||
<path d="M2.66602 4.66667L2.66602 2L3.99935 2L3.99935 4.66667L5.99935 4.66667L3.33268 7.33333L0.666016 4.66667L2.66602 4.66667Z" fill="#354052"/>
|
||||
<path d="M7.33268 2.66667H13.9993V4H7.33268V2.66667ZM7.33268 12H13.9993V13.3333H7.33268V12ZM5.99935 7.33333H13.9993V8.66667H5.99935V7.33333Z" fill="#354052"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 579 B |
@ -0,0 +1,62 @@
|
||||
{
|
||||
"icon": {
|
||||
"type": "element",
|
||||
"isRootNode": true,
|
||||
"name": "svg",
|
||||
"attributes": {
|
||||
"width": "16",
|
||||
"height": "16",
|
||||
"viewBox": "0 0 16 16",
|
||||
"fill": "none",
|
||||
"xmlns": "http://www.w3.org/2000/svg"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "g",
|
||||
"attributes": {
|
||||
"id": "Icon L"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "g",
|
||||
"attributes": {
|
||||
"id": "Vector"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"d": "M2.66602 11.3333H0.666016L3.33268 8.66667L5.99935 11.3333H3.99935L3.99935 14H2.66602L2.66602 11.3333Z",
|
||||
"fill": "currentColor"
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"d": "M2.66602 4.66667L2.66602 2L3.99935 2L3.99935 4.66667L5.99935 4.66667L3.33268 7.33333L0.666016 4.66667L2.66602 4.66667Z",
|
||||
"fill": "currentColor"
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"d": "M7.33268 2.66667H13.9993V4H7.33268V2.66667ZM7.33268 12H13.9993V13.3333H7.33268V12ZM5.99935 7.33333H13.9993V8.66667H5.99935V7.33333Z",
|
||||
"fill": "currentColor"
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "Collapse"
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
// GENERATE BY script
|
||||
// DON NOT EDIT IT MANUALLY
|
||||
|
||||
import * as React from 'react'
|
||||
import data from './Collapse.json'
|
||||
import IconBase from '@/app/components/base/icons/IconBase'
|
||||
import type { IconData } from '@/app/components/base/icons/IconBase'
|
||||
|
||||
const Icon = (
|
||||
{
|
||||
ref,
|
||||
...props
|
||||
}: React.SVGProps<SVGSVGElement> & {
|
||||
ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
|
||||
},
|
||||
) => <IconBase {...props} ref={ref} data={data as IconData} />
|
||||
|
||||
Icon.displayName = 'Collapse'
|
||||
|
||||
export default Icon
|
||||
@ -0,0 +1,97 @@
|
||||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
import {
|
||||
RiCheckLine,
|
||||
RiComputerLine,
|
||||
RiMoonLine,
|
||||
RiSunLine,
|
||||
} from '@remixicon/react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useTheme } from 'next-themes'
|
||||
import ActionButton from '@/app/components/base/action-button'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
|
||||
export type Theme = 'light' | 'dark' | 'system'
|
||||
|
||||
export default function ThemeSelector() {
|
||||
const { t } = useTranslation()
|
||||
const { theme, setTheme } = useTheme()
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
const handleThemeChange = (newTheme: Theme) => {
|
||||
setTheme(newTheme)
|
||||
setOpen(false)
|
||||
}
|
||||
|
||||
const getCurrentIcon = () => {
|
||||
switch (theme) {
|
||||
case 'light': return <RiSunLine className='h-4 w-4 text-text-tertiary' />
|
||||
case 'dark': return <RiMoonLine className='h-4 w-4 text-text-tertiary' />
|
||||
default: return <RiComputerLine className='h-4 w-4 text-text-tertiary' />
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<PortalToFollowElem
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
placement='bottom-end'
|
||||
offset={{ mainAxis: 6 }}
|
||||
>
|
||||
<PortalToFollowElemTrigger
|
||||
onClick={() => setOpen(!open)}
|
||||
>
|
||||
<ActionButton
|
||||
className={`h-8 w-8 p-[6px] ${open && 'bg-state-base-hover'}`}
|
||||
>
|
||||
{getCurrentIcon()}
|
||||
</ActionButton>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className='z-[1000]'>
|
||||
<div className='flex w-[144px] flex-col items-start rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-1 shadow-lg'>
|
||||
<button
|
||||
className='flex w-full items-center gap-1 rounded-lg px-2 py-1.5 text-text-secondary hover:bg-state-base-hover'
|
||||
onClick={() => handleThemeChange('light')}
|
||||
>
|
||||
<RiSunLine className='h-4 w-4 text-text-tertiary' />
|
||||
<div className='flex grow items-center justify-start px-1'>
|
||||
<span className='system-md-regular'>{t('common.theme.light')}</span>
|
||||
</div>
|
||||
{theme === 'light' && <div className='flex h-4 w-4 shrink-0 items-center justify-center'>
|
||||
<RiCheckLine className='h-4 w-4 text-text-accent' />
|
||||
</div>}
|
||||
</button>
|
||||
<button
|
||||
className='flex w-full items-center gap-1 rounded-lg px-2 py-1.5 text-text-secondary hover:bg-state-base-hover'
|
||||
onClick={() => handleThemeChange('dark')}
|
||||
>
|
||||
<RiMoonLine className='h-4 w-4 text-text-tertiary' />
|
||||
<div className='flex grow items-center justify-start px-1'>
|
||||
<span className='system-md-regular'>{t('common.theme.dark')}</span>
|
||||
</div>
|
||||
{theme === 'dark' && <div className='flex h-4 w-4 shrink-0 items-center justify-center'>
|
||||
<RiCheckLine className='h-4 w-4 text-text-accent' />
|
||||
</div>}
|
||||
</button>
|
||||
<button
|
||||
className='flex w-full items-center gap-1 rounded-lg px-2 py-1.5 text-text-secondary hover:bg-state-base-hover'
|
||||
onClick={() => handleThemeChange('system')}
|
||||
>
|
||||
<RiComputerLine className='h-4 w-4 text-text-tertiary' />
|
||||
<div className='flex grow items-center justify-start px-1'>
|
||||
<span className='system-md-regular'>{t('common.theme.auto')}</span>
|
||||
</div>
|
||||
{theme === 'system' && <div className='flex h-4 w-4 shrink-0 items-center justify-center'>
|
||||
<RiCheckLine className='h-4 w-4 text-text-accent' />
|
||||
</div>}
|
||||
</button>
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
</PortalToFollowElem>
|
||||
)
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
'use client'
|
||||
import {
|
||||
RiComputerLine,
|
||||
RiMoonLine,
|
||||
RiSunLine,
|
||||
} from '@remixicon/react'
|
||||
import { useTheme } from 'next-themes'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
export type Theme = 'light' | 'dark' | 'system'
|
||||
|
||||
export default function ThemeSwitcher() {
|
||||
const { theme, setTheme } = useTheme()
|
||||
|
||||
const handleThemeChange = (newTheme: Theme) => {
|
||||
setTheme(newTheme)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='flex items-center rounded-[10px] bg-components-segmented-control-bg-normal p-0.5'>
|
||||
<div
|
||||
className={cn(
|
||||
'rounded-lg px-2 py-1 text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary',
|
||||
theme === 'system' && 'bg-components-segmented-control-item-active-bg text-text-accent-light-mode-only shadow-sm hover:bg-components-segmented-control-item-active-bg hover:text-text-accent-light-mode-only',
|
||||
)}
|
||||
onClick={() => handleThemeChange('system')}
|
||||
>
|
||||
<div className='p-0.5'>
|
||||
<RiComputerLine className='h-4 w-4' />
|
||||
</div>
|
||||
</div>
|
||||
<div className={cn('h-[14px] w-px bg-transparent', theme === 'dark' && 'bg-divider-regular')}></div>
|
||||
<div
|
||||
className={cn(
|
||||
'rounded-lg px-2 py-1 text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary',
|
||||
theme === 'light' && 'bg-components-segmented-control-item-active-bg text-text-accent-light-mode-only shadow-sm hover:bg-components-segmented-control-item-active-bg hover:text-text-accent-light-mode-only',
|
||||
)}
|
||||
onClick={() => handleThemeChange('light')}
|
||||
>
|
||||
<div className='p-0.5'>
|
||||
<RiSunLine className='h-4 w-4' />
|
||||
</div>
|
||||
</div>
|
||||
<div className={cn('h-[14px] w-px bg-transparent', theme === 'system' && 'bg-divider-regular')}></div>
|
||||
<div
|
||||
className={cn(
|
||||
'rounded-lg px-2 py-1 text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary',
|
||||
theme === 'dark' && 'bg-components-segmented-control-item-active-bg text-text-accent-light-mode-only shadow-sm hover:bg-components-segmented-control-item-active-bg hover:text-text-accent-light-mode-only',
|
||||
)}
|
||||
onClick={() => handleThemeChange('dark')}
|
||||
>
|
||||
<div className='p-0.5'>
|
||||
<RiMoonLine className='h-4 w-4' />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
const translation = {
|
||||
toVerifiedTip: {
|
||||
coupon: 'exklusiver 100% Gutschein',
|
||||
end: 'für den Dify Professional Plan.',
|
||||
front: 'Sie sind jetzt berechtigt, den Status „Bildung verifiziert“ zu erhalten. Bitte geben Sie unten Ihre Bildungsinformationen ein, um den Prozess abzuschließen und eine Zu erhalten.',
|
||||
},
|
||||
form: {
|
||||
schoolName: {
|
||||
placeholder: 'Geben Sie den offiziellen, unabgekürzten Namen Ihrer Schule ein.',
|
||||
title: 'Ihr Schulname',
|
||||
},
|
||||
schoolRole: {
|
||||
option: {
|
||||
teacher: 'Lehrer',
|
||||
administrator: 'Schuladministrator',
|
||||
student: 'Schüler',
|
||||
},
|
||||
title: 'Ihre Schulrolle',
|
||||
},
|
||||
terms: {
|
||||
desc: {
|
||||
and: 'und',
|
||||
privacyPolicy: 'Datenschutzrichtlinie',
|
||||
termsOfService: 'Nutzungsbedingungen',
|
||||
end: '. Durch die Einreichung:',
|
||||
front: 'Ihre Informationen und die Nutzung des Status "Bildung bestätigt" unterliegen unseren',
|
||||
},
|
||||
option: {
|
||||
inSchool: 'Ich bestätige, dass ich an der angegebenen Einrichtung eingeschrieben oder angestellt bin. Dify kann einen Nachweis über die Einschreibung/Anstellung anfordern. Wenn ich meine Berechtigung falsch darstelle, stimme ich zu, alle Gebühren zu zahlen, die aufgrund meines Bildungsstatus ursprünglich erlassen wurden.',
|
||||
age: 'Ich bestätige, dass ich mindestens 18 Jahre alt bin.',
|
||||
},
|
||||
title: 'Allgemeine Geschäftsbedingungen',
|
||||
},
|
||||
},
|
||||
toVerified: 'Bildung überprüfen lassen',
|
||||
rejectTitle: 'Ihre Dify-Ausbildungsüberprüfung wurde abgelehnt.',
|
||||
currentSigned: 'DERZEIT ANGEMELDET ALS',
|
||||
submit: 'Einreichen',
|
||||
submitError: 'Die Formularübermittlung ist fehlgeschlagen. Bitte versuchen Sie es später erneut.',
|
||||
rejectContent: 'Leider sind Sie nicht für den Status "Education Verified" berechtigt und können daher den exklusiven 100%-Gutschein für den Dify Professional Plan nicht erhalten, wenn Sie diese E-Mail-Adresse verwenden.',
|
||||
successContent: 'Wir haben einen 100% Rabattgutschein für den Dify Professional Plan auf Ihr Konto ausgestellt. Der Gutschein ist ein Jahr lang gültig, bitte nutzen Sie ihn innerhalb des Gültigkeitszeitraums.',
|
||||
learn: 'Erfahren Sie, wie Sie Ihre Ausbildung überprüfen lassen.',
|
||||
emailLabel: 'Ihre aktuelle E-Mail',
|
||||
successTitle: 'Sie haben die Dify-Ausbildung verifiziert',
|
||||
}
|
||||
|
||||
export default translation
|
||||
@ -1,3 +1,37 @@
|
||||
const translation = {}
|
||||
const translation = {
|
||||
daysInWeek: {
|
||||
Sat: 'Sat',
|
||||
Fri: 'Freitag',
|
||||
Thu: 'Donnerstag',
|
||||
Tue: 'Tue',
|
||||
Sun: 'Sonne',
|
||||
Mon: 'Mon',
|
||||
Wed: 'Mittwoch',
|
||||
},
|
||||
months: {
|
||||
August: 'August',
|
||||
March: 'März',
|
||||
January: 'Januar',
|
||||
June: 'Juni',
|
||||
July: 'Juli',
|
||||
November: 'November',
|
||||
September: 'September',
|
||||
April: 'April',
|
||||
February: 'Februar',
|
||||
May: 'Mai',
|
||||
December: 'Dezember',
|
||||
October: 'Oktober',
|
||||
},
|
||||
operation: {
|
||||
pickDate: 'Datum auswählen',
|
||||
ok: 'OK',
|
||||
cancel: 'Stornieren',
|
||||
now: 'Jetzt',
|
||||
},
|
||||
title: {
|
||||
pickTime: 'Wähle Zeit',
|
||||
},
|
||||
defaultPlaceholder: 'Wähle eine Zeit...',
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue