Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
D
dify
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ai-tech
dify
Commits
bbbfaaff
Commit
bbbfaaff
authored
Aug 09, 2023
by
Gillian97
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: style opt & merge app settings
parent
84ef9d0c
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
92 additions
and
111 deletions
+92
-111
cardView.tsx
...yout)/app/(appDetailLayout)/[appId]/overview/cardView.tsx
+1
-3
chartView.tsx
...out)/app/(appDetailLayout)/[appId]/overview/chartView.tsx
+15
-27
AppCard.tsx
web/app/(commonLayout)/apps/AppCard.tsx
+64
-73
style.module.css
web/app/(commonLayout)/apps/style.module.css
+1
-0
appCard.tsx
web/app/components/app/overview/appCard.tsx
+3
-3
appChart.tsx
web/app/components/app/overview/appChart.tsx
+2
-1
index.tsx
web/app/components/app/overview/settings/index.tsx
+5
-3
app-overview.en.ts
web/i18n/lang/app-overview.en.ts
+1
-1
No files found.
web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/cardView.tsx
View file @
bbbfaaff
...
...
@@ -67,16 +67,14 @@ const CardView: FC<ICardViewProps> = ({ appId }) => {
}
return
(
<
div
className=
'
flex flex-row justify-between
w-full mb-6'
>
<
div
className=
'
min-w-max grid gap-6 grid-cols-1 xl:grid-cols-2
w-full mb-6'
>
<
AppCard
className=
'mr-3 flex-1'
appInfo=
{
response
}
cardType=
'webapp'
onChangeStatus=
{
onChangeSiteStatus
}
onGenerateCode=
{
onGenerateCode
}
onSaveSiteConfig=
{
onSaveSiteConfig
}
/>
<
AppCard
className=
'ml-3 flex-1'
cardType=
'api'
appInfo=
{
response
}
onChangeStatus=
{
onChangeApiStatus
}
/>
...
...
web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/chartView.tsx
View file @
bbbfaaff
...
...
@@ -46,35 +46,23 @@ export default function ChartView({ appId }: IChartViewProps) {
defaultValue=
{
7
}
/>
</
div
>
<
div
className=
'flex flex-row w-full mb-6'
>
<
div
className=
'flex-1 mr-3'
>
<
ConversationsChart
period=
{
period
}
id=
{
appId
}
/>
</
div
>
<
div
className=
'flex-1 ml-3'
>
<
EndUsersChart
period=
{
period
}
id=
{
appId
}
/>
</
div
>
<
div
className=
'grid gap-6 grid-cols-1 xl:grid-cols-2 w-full mb-6'
>
<
ConversationsChart
period=
{
period
}
id=
{
appId
}
/>
<
EndUsersChart
period=
{
period
}
id=
{
appId
}
/>
</
div
>
<
div
className=
'flex flex-row w-full mb-6'
>
<
div
className=
'flex-1 mr-3'
>
{
isChatApp
?
(
<
AvgSessionInteractions
period=
{
period
}
id=
{
appId
}
/>
)
:
(
<
AvgResponseTime
period=
{
period
}
id=
{
appId
}
/>
)
}
</
div
>
<
div
className=
'flex-1 ml-3'
>
<
TokenPerSecond
period=
{
period
}
id=
{
appId
}
/>
</
div
>
<
div
className=
'grid gap-6 grid-cols-1 xl:grid-cols-2 w-full mb-6'
>
{
isChatApp
?
(
<
AvgSessionInteractions
period=
{
period
}
id=
{
appId
}
/>
)
:
(
<
AvgResponseTime
period=
{
period
}
id=
{
appId
}
/>
)
}
<
TokenPerSecond
period=
{
period
}
id=
{
appId
}
/>
</
div
>
<
div
className=
'flex flex-row w-full mb-6'
>
<
div
className=
'flex-1 ml-3'
>
<
UserSatisfactionRate
period=
{
period
}
id=
{
appId
}
/>
</
div
>
<
div
className=
'flex-1 ml-3'
>
<
CostChart
period=
{
period
}
id=
{
appId
}
/>
</
div
>
<
div
className=
'grid gap-6 grid-cols-1 xl:grid-cols-2 w-full mb-6'
>
<
UserSatisfactionRate
period=
{
period
}
id=
{
appId
}
/>
<
CostChart
period=
{
period
}
id=
{
appId
}
/>
</
div
>
</
div
>
)
...
...
web/app/(commonLayout)/apps/AppCard.tsx
View file @
bbbfaaff
...
...
@@ -2,22 +2,22 @@
import
{
useContext
,
useContextSelector
}
from
'use-context-selector'
import
Link
from
'next/link'
import
type
{
MouseEventHandler
}
from
'react'
import
{
useCallback
,
useState
}
from
'react'
import
{
useTranslation
}
from
'react-i18next'
import
cn
from
'classnames'
import
style
from
'../list.module.css'
import
AppModeLabel
from
'./AppModeLabel'
import
AppSettings
from
'./AppSettings'
import
s
from
'./style.module.css'
import
SettingsModal
from
'@/app/components/app/overview/settings'
import
type
{
App
}
from
'@/types/app'
import
Confirm
from
'@/app/components/base/confirm'
import
{
ToastContext
}
from
'@/app/components/base/toast'
import
{
deleteApp
,
updateAppIcon
,
updateAppName
}
from
'@/service/apps'
import
{
deleteApp
,
fetchAppDetail
,
updateAppSiteConfig
}
from
'@/service/apps'
import
AppIcon
from
'@/app/components/base/app-icon'
import
AppsContext
from
'@/context/app-context'
import
CustomPopover
from
'@/app/components/base/popover'
import
Divider
from
'@/app/components/base/divider'
import
{
asyncRunSafe
}
from
'@/utils'
export
type
AppCardProps
=
{
app
:
App
...
...
@@ -35,17 +35,10 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => {
const
[
showConfirmDelete
,
setShowConfirmDelete
]
=
useState
(
false
)
const
[
showSettingsModal
,
setShowSettingsModal
]
=
useState
(
false
)
const
[
updateLoading
,
setUpdateLoading
]
=
useState
(
false
)
const
onClickSettings
:
MouseEventHandler
=
useCallback
((
e
)
=>
{
e
.
preventDefault
()
setShowSettingsModal
(
true
)
},
[])
const
onClickDelete
:
MouseEventHandler
=
useCallback
((
e
)
=>
{
e
.
preventDefault
()
setShowConfirmDelete
(
true
)
},
[])
const
[
detailState
,
setDetailState
]
=
useState
<
{
loading
:
boolean
detail
?:
App
}
>
({
loading
:
false
})
const
onConfirmDelete
=
useCallback
(
async
()
=>
{
try
{
...
...
@@ -66,34 +59,34 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => {
setShowConfirmDelete
(
false
)
},
[
app
.
id
])
const
onUpdate
=
useCallback
(
async
(
params
:
{
name
:
App
[
'name'
];
iconInfo
:
{
icon
:
string
;
icon_background
:
string
}
})
=>
{
const
reqList
=
[]
if
(
params
.
name
!==
app
.
name
)
{
reqList
.
push
(
updateAppName
({
url
:
`/apps/
${
app
.
id
}
/name`
,
body
:
{
name
:
params
.
name
},
})
)
}
if
(
params
.
iconInfo
.
icon
!==
app
.
icon
||
params
.
iconInfo
.
icon_background
!==
app
.
icon_background
)
reqList
.
push
(
updateAppIcon
({
url
:
`/apps/
${
app
.
id
}
/icon`
,
body
:
params
.
iconInfo
}))
const
getAppDetail
=
async
()
=>
{
setDetailState
({
loading
:
true
})
const
[
err
,
res
]
=
await
asyncRunSafe
<
App
>
(
fetchAppDetail
({
url
:
'/apps'
,
id
:
app
.
id
})
as
Promise
<
App
>
,
)
if
(
!
err
)
{
setDetailState
({
loading
:
false
,
detail
:
res
})
setShowSettingsModal
(
true
)
}
else
{
setDetailState
({
loading
:
false
})
}
}
if
(
!
reqList
.
length
)
{
setShowSettingsModal
(
false
)
notify
({
type
:
'info'
,
message
:
t
(
'common.actionMsg.noModification'
),
})
return
}
setUpdateLoading
(
true
)
const
updateRes
=
await
Promise
.
allSettled
(
reqList
)
if
(
!
updateRes
.
find
(
v
=>
v
.
status
===
'rejected'
))
{
const
onSaveSiteConfig
=
useCallback
(
async
(
params
:
any
)
=>
{
const
[
err
]
=
await
asyncRunSafe
<
App
>
(
updateAppSiteConfig
({
url
:
`/apps/
${
app
.
id
}
/site`
,
body
:
params
,
})
as
Promise
<
App
>
,
)
if
(
!
err
)
{
notify
({
type
:
'success'
,
message
:
t
(
'common.actionMsg.modifiedSuccessfully'
),
})
setShowSettingsModal
(
false
)
if
(
onRefresh
)
onRefresh
()
mutateApps
()
}
else
{
notify
({
...
...
@@ -101,44 +94,45 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => {
message
:
t
(
'common.actionMsg.modificationFailed'
),
})
}
if
(
onRefresh
)
onRefresh
()
mutateApps
()
setUpdateLoading
(
false
)
},
[
app
.
id
],
)
const
Operations
=
(
props
:
any
)
=>
{
return
<
div
className=
"w-full py-1"
>
<
div
className=
{
s
.
actionItem
}
onClick=
{
(
e
)
=>
{
props
?.
onClose
()
onClickSettings
(
e
)
}
}
>
<
span
className=
{
s
.
actionName
}
>
{
t
(
'common.operation.settings'
)
}
</
span
>
</
div
>
<
Divider
className=
"my-1"
/>
<
div
className=
{
cn
(
s
.
actionItem
,
s
.
deleteActionItem
,
'group'
)
}
onClick=
{
(
e
)
=>
{
props
?.
onClose
()
onClickDelete
(
e
)
}
}
>
<
span
className=
{
cn
(
s
.
actionName
,
'group-hover:text-red-500'
)
}
const
onClickSettings
=
async
(
e
:
any
)
=>
{
props
?.
onClose
()
e
.
preventDefault
()
await
getAppDetail
(
)
}
const
onClickDelete
=
async
(
e
:
any
)
=>
{
props
?.
onClose
()
e
.
preventDefault
()
setShowConfirmDelete
(
true
)
}
return
(
<
div
className=
"w-full py-1"
>
<
button
className=
{
s
.
actionItem
}
onClick=
{
onClickSettings
}
disabled=
{
detailState
.
loading
}
>
<
span
className=
{
s
.
actionName
}
>
{
t
(
'common.operation.settings'
)
}
</
span
>
</
button
>
<
Divider
className=
"!my-1"
/>
<
div
className=
{
cn
(
s
.
actionItem
,
s
.
deleteActionItem
,
'group'
)
}
onClick=
{
onClickDelete
}
>
{
t
(
'common.operation.delete'
)
}
</
span
>
<
span
className=
{
cn
(
s
.
actionName
,
'group-hover:text-red-500'
)
}
>
{
t
(
'common.operation.delete'
)
}
</
span
>
</
div
>
</
div
>
</
div
>
)
}
return
(
<>
<
Link
href=
{
`/app/${app.id}/overview`
}
className=
{
style
.
listItem
}
>
<
Link
href=
{
`/app/${app.id}/overview`
}
className=
{
style
.
listItem
}
>
<
div
className=
{
style
.
listItemTitle
}
>
<
AppIcon
size=
"small"
...
...
@@ -149,10 +143,9 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => {
<
div
className=
{
style
.
listItemHeadingContent
}
>
{
app
.
name
}
</
div
>
</
div
>
<
CustomPopover
htmlContent=
{
<
Operations
/>
}
htmlContent=
{
<
Operations
/>
}
position=
"br"
trigger=
"click"
btnElement=
{
<
div
className=
{
cn
(
s
.
actionIcon
,
s
.
commonIcon
)
}
/>
}
btnClassName=
{
open
=>
cn
(
...
...
@@ -180,14 +173,12 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => {
onCancel=
{
()
=>
setShowConfirmDelete
(
false
)
}
/>
)
}
{
showSettingsModal
&&
(
<
AppSettings
{
showSettingsModal
&&
detailState
.
detail
&&
(
<
SettingsModal
appInfo=
{
detailState
.
detail
}
isShow=
{
showSettingsModal
}
onClose=
{
()
=>
setShowSettingsModal
(
false
)
}
appName=
{
app
.
name
}
appIcon=
{
{
icon
:
app
.
icon
,
icon_background
:
app
.
icon_background
}
}
onUpdate=
{
onUpdate
}
loading=
{
updateLoading
}
onSave=
{
onSaveSiteConfig
}
/>
)
}
</
Link
>
...
...
web/app/(commonLayout)/apps/style.module.css
View file @
bbbfaaff
...
...
@@ -11,6 +11,7 @@
}
.actionItem
{
@apply
h-9
py-2
px-3
mx-1
flex
items-center
gap-2
hover
:
bg-gray-100
rounded-lg
cursor-pointer
;
width
:
calc
(
100%
-
0.5rem
);
}
.deleteActionItem
{
@apply
hover
:
bg-red-50
!important
;
...
...
web/app/components/app/overview/appCard.tsx
View file @
bbbfaaff
...
...
@@ -134,11 +134,11 @@ function AppCard({
return
(
<
div
className=
{
`
flex flex-col w-full
shadow-sm border-[0.5px] rounded-lg border-gray-200 ${
className=
{
`
min-w-max
shadow-sm border-[0.5px] rounded-lg border-gray-200 ${
className ?? ''
}`
}
>
<
div
className=
{
`px-6 py-
4
${customBgColor ?? bgColor} rounded-lg`
}
>
<
div
className=
{
`px-6 py-
5
${customBgColor ?? bgColor} rounded-lg`
}
>
<
div
className=
"mb-2.5 flex flex-row items-start justify-between"
>
<
AppBasic
iconType=
{
cardType
}
...
...
@@ -208,7 +208,7 @@ function AppCard({
:
!
runningStatus
return
(
<
Button
className=
"mr-2 border-[0.5px] hover:outline hover:outline-[0.5px] hover:outline-gray-300 text-gray-700 font-medium bg-white shadow-[0px_1px_2px_0px_rgba(16,24,40,0.05)]"
className=
"mr-2 border-[0.5px]
!h-8
hover:outline hover:outline-[0.5px] hover:outline-gray-300 text-gray-700 font-medium bg-white shadow-[0px_1px_2px_0px_rgba(16,24,40,0.05)]"
key=
{
op
.
opName
}
onClick=
{
genClickFuncByName
(
op
.
opName
)
}
disabled=
{
disabled
}
...
...
web/app/components/app/overview/appChart.tsx
View file @
bbbfaaff
...
...
@@ -229,7 +229,7 @@ const Chart: React.FC<IChartProps> = ({
<
div
className=
'mb-3'
>
<
Basic
name=
{
title
}
type=
{
timePeriod
}
hoverTip=
{
explanation
}
/>
</
div
>
<
div
className=
'mb-4'
>
<
div
className=
'mb-4
flex-1
'
>
<
Basic
isExtraInLine=
{
CHART_TYPE_CONFIG
[
chartType
].
showTokens
}
name=
{
chartType
!==
'costs'
?
(
sumData
.
toLocaleString
()
+
unit
)
:
`${sumData < 1000 ? sumData : (`
$
{
formatNumber
(
Math
.
round
(
sumData
/
1000
))}
k
`)}`
}
...
...
@@ -347,6 +347,7 @@ export const UserSatisfactionRate: FC<IBizChartProps> = ({ id, period }) => {
chartType=
'endUsers'
isAvg
{
...
(
noDataFlag
&&
{
yMax
:
1000
})}
className=
'h-full'
/>
}
...
...
web/app/components/app/overview/settings/index.tsx
View file @
bbbfaaff
...
...
@@ -18,7 +18,7 @@ export type ISettingsModalProps = {
isShow
:
boolean
defaultValue
?:
string
onClose
:
()
=>
void
onSave
:
(
params
:
ConfigParams
)
=>
Promise
<
any
>
onSave
?
:
(
params
:
ConfigParams
)
=>
Promise
<
any
>
}
export
type
ConfigParams
=
{
...
...
@@ -70,7 +70,7 @@ const SettingsModal: FC<ISettingsModalProps> = ({
icon
:
emoji
.
icon
,
icon_background
:
emoji
.
icon_background
,
}
await
onSave
(
params
)
await
onSave
?.
(
params
)
setSaveLoading
(
false
)
onHide
()
}
...
...
@@ -99,7 +99,9 @@ const SettingsModal: FC<ISettingsModalProps> = ({
/>
<
input
className=
{
`flex-grow rounded-lg h-10 box-border px-3 ${s.projectName} bg-gray-100`
}
value=
{
inputInfo
.
title
}
onChange=
{
onChange
(
'title'
)
}
/>
onChange=
{
onChange
(
'title'
)
}
placeholder=
{
t
(
'app.appNamePlaceholder'
)
||
''
}
/>
</
div
>
<
div
className=
{
`mt-6 font-medium ${s.settingTitle} text-gray-900 `
}
>
{
t
(
`${prefixSettings}.webDesc`
)
}
</
div
>
<
p
className=
{
`mt-1 ${s.settingsTip} text-gray-500`
}
>
{
t
(
`${prefixSettings}.webDescTip`
)
}
</
p
>
...
...
web/i18n/lang/app-overview.en.ts
View file @
bbbfaaff
...
...
@@ -64,7 +64,7 @@ const translation = {
apiInfo
:
{
title
:
'Backend service API'
,
explanation
:
'Easily integrated into your application'
,
accessibleAddress
:
'
API Token
'
,
accessibleAddress
:
'
Service API Endpoint
'
,
doc
:
'API Reference'
,
},
status
:
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment