fix: better qr code panel and webapp url regen confirmation (#6321)

This commit is contained in:
Charles Zhou 2024-07-16 02:06:49 -05:00 committed by GitHub
parent 55d7374ab7
commit 0099ef6896
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 53 additions and 33 deletions

View File

@ -183,7 +183,7 @@ function AppCard({
<Confirm <Confirm
type='warning' type='warning'
title={t('appOverview.overview.appInfo.regenerate')} title={t('appOverview.overview.appInfo.regenerate')}
content={''} content={t('appOverview.overview.appInfo.regenerateNotice')}
isShow={showConfirmDelete} isShow={showConfirmDelete}
onClose={() => setShowConfirmDelete(false)} onClose={() => setShowConfirmDelete(false)}
onConfirm={() => { onConfirm={() => {

View File

@ -1,7 +1,6 @@
'use client' 'use client'
import React, { useState } from 'react' import React, { useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { debounce } from 'lodash-es'
import QRCode from 'qrcode.react' import QRCode from 'qrcode.react'
import Tooltip from '../tooltip' import Tooltip from '../tooltip'
import QrcodeStyle from './style.module.css' import QrcodeStyle from './style.module.css'
@ -16,10 +15,27 @@ const prefixEmbedded = 'appOverview.overview.appInfo.qrcode.title'
const ShareQRCode = ({ content, selectorId, className }: Props) => { const ShareQRCode = ({ content, selectorId, className }: Props) => {
const { t } = useTranslation() const { t } = useTranslation()
const [isShow, setisShow] = useState<boolean>(false) const [isShow, setIsShow] = useState<boolean>(false)
const onClickShow = debounce(() => { const qrCodeRef = useRef<HTMLDivElement>(null)
setisShow(true)
}, 100) const toggleQRCode = (event: React.MouseEvent) => {
event.stopPropagation()
setIsShow(prev => !prev)
}
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (qrCodeRef.current && !qrCodeRef.current.contains(event.target as Node))
setIsShow(false)
}
if (isShow)
document.addEventListener('click', handleClickOutside)
return () => {
document.removeEventListener('click', handleClickOutside)
}
}, [isShow])
const downloadQR = () => { const downloadQR = () => {
const canvas = document.getElementsByTagName('canvas')[0] const canvas = document.getElementsByTagName('canvas')[0]
@ -29,9 +45,9 @@ const ShareQRCode = ({ content, selectorId, className }: Props) => {
link.click() link.click()
} }
const onMouseLeave = debounce(() => { const handlePanelClick = (event: React.MouseEvent) => {
setisShow(false) event.stopPropagation()
}, 500) }
return ( return (
<Tooltip <Tooltip
@ -40,19 +56,23 @@ const ShareQRCode = ({ content, selectorId, className }: Props) => {
> >
<div <div
className={`w-8 h-8 cursor-pointer rounded-lg ${className ?? ''}`} className={`w-8 h-8 cursor-pointer rounded-lg ${className ?? ''}`}
onMouseLeave={onMouseLeave} onClick={toggleQRCode}
onClick={onClickShow}
> >
<div className={`w-full h-full ${QrcodeStyle.QrcodeIcon} ${isShow ? QrcodeStyle.show : ''}`} /> <div className={`w-full h-full ${QrcodeStyle.QrcodeIcon} ${isShow ? QrcodeStyle.show : ''}`} />
{isShow && <div className={QrcodeStyle.qrcodeform}> {isShow && (
<QRCode size={160} value={content} className={QrcodeStyle.qrcodeimage}/> <div
<div className={QrcodeStyle.text}> ref={qrCodeRef}
<div className={`text-gray-500 ${QrcodeStyle.scan}`}>{t('appOverview.overview.appInfo.qrcode.scan')}</div> className={QrcodeStyle.qrcodeform}
<div className={`text-gray-500 ${QrcodeStyle.scan}`}>·</div> onClick={handlePanelClick}
<div className={QrcodeStyle.download} onClick={downloadQR}>{t('appOverview.overview.appInfo.qrcode.download')}</div> >
<QRCode size={160} value={content} className={QrcodeStyle.qrcodeimage}/>
<div className={QrcodeStyle.text}>
<div className={`text-gray-500 ${QrcodeStyle.scan}`}>{t('appOverview.overview.appInfo.qrcode.scan')}</div>
<div className={`text-gray-500 ${QrcodeStyle.scan}`}>·</div>
<div className={QrcodeStyle.download} onClick={downloadQR}>{t('appOverview.overview.appInfo.qrcode.download')}</div>
</div>
</div> </div>
</div> )}
}
</div> </div>
</Tooltip> </Tooltip>
) )

View File

@ -37,6 +37,7 @@
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
white-space: nowrap;
gap: 4px; gap: 4px;
} }
.qrcodeform { .qrcodeform {
@ -46,7 +47,8 @@
margin: 0 !important; margin: 0 !important;
margin-top: 4px !important; margin-top: 4px !important;
margin-left: -75px !important; margin-left: -75px !important;
position: absolute; width: fit-content;
position: relative;
border-radius: 8px; border-radius: 8px;
background-color: #fff; background-color: #fff;
box-shadow: 0 12px 16px -4px rgba(16, 24, 40, 0.08), box-shadow: 0 12px 16px -4px rgba(16, 24, 40, 0.08),
@ -54,8 +56,6 @@
overflow: hidden; overflow: hidden;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding: 12px; padding: 15px;
gap: 8px; gap: 8px;
z-index: 3;
font-family: "PingFang SC", serif;
} }

View File

@ -3,23 +3,23 @@ const translation = {
firstStepTip: 'To get started,', firstStepTip: 'To get started,',
enterKeyTip: 'enter your OpenAI API Key below', enterKeyTip: 'enter your OpenAI API Key below',
getKeyTip: 'Get your API Key from OpenAI dashboard', getKeyTip: 'Get your API Key from OpenAI dashboard',
placeholder: 'Your OpenAI API Key(eg.sk-xxxx)', placeholder: 'Your OpenAI API Key (eg.sk-xxxx)',
}, },
apiKeyInfo: { apiKeyInfo: {
cloud: { cloud: {
trial: { trial: {
title: 'You are using the {{providerName}} trial quota.', title: 'You are using the {{providerName}} trial quota.',
description: 'The trial quota is provided for your testing use. Before the trial quota calls are exhausted, please set up your own model provider or purchase additional quota.', description: 'The trial quota is provided for your testing purposes. Before the trial quota is exhausted, please set up your own model provider or purchase additional quota.',
}, },
exhausted: { exhausted: {
title: 'Your trial quota have been used up, please set up your APIKey.', title: 'Your trial quota have been used up, please set up your APIKey.',
description: 'Your trial quota has been exhausted. Please set up your own model provider or purchase additional quota.', description: 'You have exhausted your trial quota. Please set up your own model provider or purchase additional quota.',
}, },
}, },
selfHost: { selfHost: {
title: { title: {
row1: 'To get started,', row1: 'To get started,',
row2: 'setup your model provider first.', row2: 'setup your model provider first.',
}, },
}, },
callTimes: 'Call times', callTimes: 'Call times',
@ -76,8 +76,8 @@ const translation = {
copy: 'Copy', copy: 'Copy',
}, },
qrcode: { qrcode: {
title: 'QR code to share', title: 'Link QR Code',
scan: 'Scan Share Application', scan: 'Scan To Share',
download: 'Download QR Code', download: 'Download QR Code',
}, },
customize: { customize: {
@ -103,14 +103,14 @@ const translation = {
}, },
}, },
apiInfo: { apiInfo: {
title: 'Backend service API', title: 'Backend Service API',
explanation: 'Easily integrated into your application', explanation: 'Easily integrated into your application',
accessibleAddress: 'Service API Endpoint', accessibleAddress: 'Service API Endpoint',
doc: 'API Reference', doc: 'API Reference',
}, },
status: { status: {
running: 'In service', running: 'In Service',
disable: 'Disable', disable: 'Disabled',
}, },
}, },
analysis: { analysis: {