mirror of
https://github.com/Awuqing/BackupX.git
synced 2026-09-05 15:37:03 +08:00
refactor(ui): 统一 SVG 图标组件
建立本地图标出口,统一项目内 Arco SVG 图标依赖并抽取登录页服务器插画。 以可复用的存储目标名称组件替换字符星标,补充可访问语义与组件测试。
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import { Alert, Button, Divider, Drawer, Input, InputNumber, Select, Space, Steps, Switch, Typography, Grid } from '@arco-design/web-react'
|
import { Alert, Button, Divider, Drawer, Input, InputNumber, Select, Space, Steps, Switch, Typography, Grid } from '@arco-design/web-react'
|
||||||
import { IconDelete, IconPlus } from '@arco-design/web-react/icon'
|
import { IconDelete, IconPlus } from '../icons'
|
||||||
import { useEffect, useMemo, useState } from 'react'
|
import { useEffect, useMemo, useState } from 'react'
|
||||||
import { CronInput } from '../CronInput'
|
import { CronInput } from '../CronInput'
|
||||||
import type { StorageTargetDetail, StorageTargetPayload, StorageTargetSummary } from '../../types/storage-targets'
|
import type { StorageTargetDetail, StorageTargetPayload, StorageTargetSummary } from '../../types/storage-targets'
|
||||||
@@ -9,6 +9,7 @@ import type { NodeSummary } from '../../types/nodes'
|
|||||||
import { DatabasePicker } from '../common/DatabasePicker'
|
import { DatabasePicker } from '../common/DatabasePicker'
|
||||||
import { DirectoryPicker } from '../common/DirectoryPicker'
|
import { DirectoryPicker } from '../common/DirectoryPicker'
|
||||||
import { StorageTargetFormDrawer } from '../storage-targets/StorageTargetFormDrawer'
|
import { StorageTargetFormDrawer } from '../storage-targets/StorageTargetFormDrawer'
|
||||||
|
import { StorageTargetName } from '../storage-targets/StorageTargetName'
|
||||||
import { SourceServerSelector } from './SourceServerSelector'
|
import { SourceServerSelector } from './SourceServerSelector'
|
||||||
import {
|
import {
|
||||||
backupCompressionOptions,
|
backupCompressionOptions,
|
||||||
@@ -169,7 +170,7 @@ export function BackupTaskFormDrawer({ visible, loading, initialValue, storageTa
|
|||||||
return 0
|
return 0
|
||||||
})
|
})
|
||||||
return sorted.map((item) => ({
|
return sorted.map((item) => ({
|
||||||
label: item.starred ? `★ ${item.name}` : item.name,
|
label: <StorageTargetName name={item.name} starred={item.starred} />,
|
||||||
value: item.id,
|
value: item.id,
|
||||||
disabled: !item.enabled,
|
disabled: !item.enabled,
|
||||||
}))
|
}))
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Button, Input, Message, Modal, Space, Spin, Tree, Typography, Empty } from '@arco-design/web-react'
|
import { Button, Input, Message, Modal, Space, Spin, Tree, Typography, Empty } from '@arco-design/web-react'
|
||||||
import { IconFolder, IconFile, IconFolderAdd } from '@arco-design/web-react/icon'
|
import { IconFolder, IconFile, IconFolderAdd } from '../icons'
|
||||||
import { useCallback, useState } from 'react'
|
import { useCallback, useState } from 'react'
|
||||||
import { listNodeDirectory } from '../../services/nodes'
|
import { listNodeDirectory } from '../../services/nodes'
|
||||||
import type { DirEntry } from '../../types/nodes'
|
import type { DirEntry } from '../../types/nodes'
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Badge, Button, Drawer, Empty, Notification, Space, Tag, Typography } from '@arco-design/web-react'
|
import { Badge, Button, Drawer, Empty, Notification, Space, Tag, Typography } from '@arco-design/web-react'
|
||||||
import { IconNotification } from '@arco-design/web-react/icon'
|
import { IconNotification } from '../icons'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { useEventStream, type SystemEvent } from '../../hooks/useEventStream'
|
import { useEventStream, type SystemEvent } from '../../hooks/useEventStream'
|
||||||
import { useEventStore } from '../../stores/events'
|
import { useEventStore } from '../../stores/events'
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Empty, Input, Modal, Space, Spin, Tag, Typography } from '@arco-design/web-react'
|
import { Empty, Input, Modal, Space, Spin, Tag, Typography } from '@arco-design/web-react'
|
||||||
import { IconSearch } from '@arco-design/web-react/icon'
|
import { IconSearch } from '../icons'
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import { globalSearch, type SearchKind, type SearchResult, type SearchResultItem } from '../../services/search'
|
import { globalSearch, type SearchKind, type SearchResult, type SearchResultItem } from '../../services/search'
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import type { SVGProps } from 'react'
|
||||||
|
|
||||||
|
export function BackupServerIllustration(props: SVGProps<SVGSVGElement>) {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width="320"
|
||||||
|
height="320"
|
||||||
|
viewBox="0 0 320 320"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
aria-hidden="true"
|
||||||
|
focusable="false"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<circle cx="160" cy="160" r="120" fill="white" fillOpacity="0.05">
|
||||||
|
<animate attributeName="r" values="115;125;115" dur="4s" repeatCount="indefinite" />
|
||||||
|
<animate attributeName="fill-opacity" values="0.03;0.08;0.03" dur="4s" repeatCount="indefinite" />
|
||||||
|
</circle>
|
||||||
|
<circle cx="160" cy="160" r="80" fill="white" fillOpacity="0.1">
|
||||||
|
<animate attributeName="r" values="75;85;75" dur="3s" repeatCount="indefinite" />
|
||||||
|
</circle>
|
||||||
|
|
||||||
|
<g>
|
||||||
|
<animateTransform attributeName="transform" type="translate" values="0,0; 0,-8; 0,0" dur="5s" repeatCount="indefinite" />
|
||||||
|
<path d="M120 120C120 111.163 137.909 104 160 104C182.091 104 200 111.163 200 120V144C200 152.837 182.091 160 160 160C137.909 160 120 152.837 120 144V120Z" fill="white" fillOpacity="0.95" />
|
||||||
|
<ellipse cx="160" cy="120" rx="40" ry="16" fill="white" />
|
||||||
|
<path d="M120 152C120 143.163 137.909 136 160 136C182.091 136 200 143.163 200 152V176C200 184.837 182.091 192 160 192C137.909 192 120 184.837 120 176V152Z" fill="white" fillOpacity="0.75" />
|
||||||
|
<ellipse cx="160" cy="152" rx="40" ry="16" fill="white" fillOpacity="0.9" />
|
||||||
|
<path d="M120 184C120 175.163 137.909 168 160 168C182.091 168 200 175.163 200 184V208C200 216.837 182.091 224 160 224C137.909 224 120 216.837 120 208V184Z" fill="white" fillOpacity="0.5" />
|
||||||
|
<ellipse cx="160" cy="184" rx="40" ry="16" fill="white" fillOpacity="0.6" />
|
||||||
|
|
||||||
|
<g fill="var(--color-primary-6, #165dff)">
|
||||||
|
<circle cx="140" cy="120" r="4">
|
||||||
|
<animate attributeName="opacity" values="0.3;1;0.3" dur="2s" begin="0s" repeatCount="indefinite" />
|
||||||
|
</circle>
|
||||||
|
<circle cx="140" cy="152" r="4">
|
||||||
|
<animate attributeName="opacity" values="0.3;1;0.3" dur="2s" begin="0.6s" repeatCount="indefinite" />
|
||||||
|
</circle>
|
||||||
|
<circle cx="140" cy="184" r="4">
|
||||||
|
<animate attributeName="opacity" values="0.3;1;0.3" dur="2s" begin="1.2s" repeatCount="indefinite" />
|
||||||
|
</circle>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<path d="M160 120V152V184" stroke="var(--color-primary-6, #165dff)" strokeWidth="2" strokeDasharray="4 4" opacity="0.6">
|
||||||
|
<animate attributeName="stroke-dashoffset" from="16" to="0" dur="1s" repeatCount="indefinite" />
|
||||||
|
</path>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
export {
|
||||||
|
IconBook,
|
||||||
|
IconCheckCircle,
|
||||||
|
IconCloud,
|
||||||
|
IconCloudDownload,
|
||||||
|
IconCommand,
|
||||||
|
IconCopy,
|
||||||
|
IconDashboard,
|
||||||
|
IconDelete,
|
||||||
|
IconDesktop,
|
||||||
|
IconDown,
|
||||||
|
IconDownload,
|
||||||
|
IconEdit,
|
||||||
|
IconFile,
|
||||||
|
IconFilePdf,
|
||||||
|
IconFolder,
|
||||||
|
IconFolderAdd,
|
||||||
|
IconHistory,
|
||||||
|
IconInfoCircle,
|
||||||
|
IconList,
|
||||||
|
IconLock,
|
||||||
|
IconMenuFold,
|
||||||
|
IconMenuUnfold,
|
||||||
|
IconMore,
|
||||||
|
IconNotification,
|
||||||
|
IconPlus,
|
||||||
|
IconPoweroff,
|
||||||
|
IconRefresh,
|
||||||
|
IconSafe,
|
||||||
|
IconSave,
|
||||||
|
IconSearch,
|
||||||
|
IconSettings,
|
||||||
|
IconStarFill,
|
||||||
|
IconStorage,
|
||||||
|
IconUser,
|
||||||
|
} from '@arco-design/web-react/icon'
|
||||||
|
|
||||||
|
export { BackupServerIllustration } from './BackupServerIllustration'
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { render, screen } from '@testing-library/react'
|
||||||
|
import { describe, expect, it } from 'vitest'
|
||||||
|
import { StorageTargetName } from './StorageTargetName'
|
||||||
|
|
||||||
|
describe('StorageTargetName', () => {
|
||||||
|
it('uses an SVG icon for starred targets without character symbols', () => {
|
||||||
|
const { container } = render(<StorageTargetName name="Central storage" starred />)
|
||||||
|
|
||||||
|
expect(screen.getByText('Central storage')).toBeInTheDocument()
|
||||||
|
expect(screen.getByLabelText('Central storage,已收藏')).toBeInTheDocument()
|
||||||
|
expect(container.querySelector('svg')).not.toBeNull()
|
||||||
|
expect(container.textContent).not.toContain(String.fromCodePoint(0x2605))
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { IconStarFill } from '../icons'
|
||||||
|
|
||||||
|
interface StorageTargetNameProps {
|
||||||
|
name: string
|
||||||
|
starred?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export function StorageTargetName({ name, starred = false }: StorageTargetNameProps) {
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
aria-label={starred ? `${name},已收藏` : undefined}
|
||||||
|
style={{ display: 'inline-flex', alignItems: 'center', gap: 4 }}
|
||||||
|
>
|
||||||
|
{starred ? <IconStarFill /> : null}
|
||||||
|
<span>{name}</span>
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -21,7 +21,7 @@ import {
|
|||||||
IconDesktop,
|
IconDesktop,
|
||||||
IconList,
|
IconList,
|
||||||
IconFilePdf,
|
IconFilePdf,
|
||||||
} from '@arco-design/web-react/icon'
|
} from '../components/icons'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { Outlet, useLocation, useNavigate } from 'react-router-dom'
|
import { Outlet, useLocation, useNavigate } from 'react-router-dom'
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
IconDashboard,
|
IconDashboard,
|
||||||
IconInfoCircle,
|
IconInfoCircle,
|
||||||
IconPoweroff,
|
IconPoweroff,
|
||||||
} from '@arco-design/web-react/icon';
|
} from '../components/icons';
|
||||||
import { Outlet, useLocation, useNavigate } from 'react-router-dom';
|
import { Outlet, useLocation, useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import { useAuthStore } from '../stores/auth';
|
import { useAuthStore } from '../stores/auth';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Alert, Avatar, Card, Empty, Grid, PageHeader, Space, Table, Tag, Typography } from '@arco-design/web-react'
|
import { Alert, Avatar, Card, Empty, Grid, PageHeader, Space, Table, Tag, Typography } from '@arco-design/web-react'
|
||||||
import { IconCheckCircle, IconDesktop, IconHistory, IconSafe, IconSave, IconStorage } from '@arco-design/web-react/icon'
|
import { IconCheckCircle, IconDesktop, IconHistory, IconSafe, IconSave, IconStorage } from '../../components/icons'
|
||||||
import ReactEChartsCore from 'echarts-for-react/lib/core'
|
import ReactEChartsCore from 'echarts-for-react/lib/core'
|
||||||
import * as echarts from 'echarts/core'
|
import * as echarts from 'echarts/core'
|
||||||
import { BarChart, LineChart, PieChart } from 'echarts/charts'
|
import { BarChart, LineChart, PieChart } from 'echarts/charts'
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Button, Checkbox, Form, Input, Space, Typography, Message } from '@arco-design/web-react'
|
import { Button, Checkbox, Form, Input, Space, Typography, Message } from '@arco-design/web-react'
|
||||||
import { IconCloud, IconLock, IconSafe, IconUser } from '@arco-design/web-react/icon'
|
import { BackupServerIllustration, IconCloud, IconLock, IconSafe, IconUser } from '../../components/icons'
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
@@ -200,41 +200,7 @@ export function LoginPage() {
|
|||||||
<div className="login-container">
|
<div className="login-container">
|
||||||
<div className="login-banner">
|
<div className="login-banner">
|
||||||
<div className="login-banner-inner">
|
<div className="login-banner-inner">
|
||||||
<svg width="320" height="320" viewBox="0 0 320 320" fill="none" xmlns="http://www.w3.org/2000/svg" style={{ marginBottom: 16 }}>
|
<BackupServerIllustration style={{ marginBottom: 16 }} />
|
||||||
<circle cx="160" cy="160" r="120" fill="white" fillOpacity="0.05">
|
|
||||||
<animate attributeName="r" values="115;125;115" dur="4s" repeatCount="indefinite" />
|
|
||||||
<animate attributeName="fill-opacity" values="0.03;0.08;0.03" dur="4s" repeatCount="indefinite" />
|
|
||||||
</circle>
|
|
||||||
<circle cx="160" cy="160" r="80" fill="white" fillOpacity="0.1">
|
|
||||||
<animate attributeName="r" values="75;85;75" dur="3s" repeatCount="indefinite" />
|
|
||||||
</circle>
|
|
||||||
|
|
||||||
<g>
|
|
||||||
<animateTransform attributeName="transform" type="translate" values="0,0; 0,-8; 0,0" dur="5s" repeatCount="indefinite" />
|
|
||||||
<path d="M120 120C120 111.163 137.909 104 160 104C182.091 104 200 111.163 200 120V144C200 152.837 182.091 160 160 160C137.909 160 120 152.837 120 144V120Z" fill="white" fillOpacity="0.95" />
|
|
||||||
<ellipse cx="160" cy="120" rx="40" ry="16" fill="white" />
|
|
||||||
<path d="M120 152C120 143.163 137.909 136 160 136C182.091 136 200 143.163 200 152V176C200 184.837 182.091 192 160 192C137.909 192 120 184.837 120 176V152Z" fill="white" fillOpacity="0.75" />
|
|
||||||
<ellipse cx="160" cy="152" rx="40" ry="16" fill="white" fillOpacity="0.9" />
|
|
||||||
<path d="M120 184C120 175.163 137.909 168 160 168C182.091 168 200 175.163 200 184V208C200 216.837 182.091 224 160 224C137.909 224 120 216.837 120 208V184Z" fill="white" fillOpacity="0.5" />
|
|
||||||
<ellipse cx="160" cy="184" rx="40" ry="16" fill="white" fillOpacity="0.6" />
|
|
||||||
|
|
||||||
<g fill="var(--color-primary-6, #165dff)">
|
|
||||||
<circle cx="140" cy="120" r="4">
|
|
||||||
<animate attributeName="opacity" values="0.3;1;0.3" dur="2s" begin="0s" repeatCount="indefinite" />
|
|
||||||
</circle>
|
|
||||||
<circle cx="140" cy="152" r="4">
|
|
||||||
<animate attributeName="opacity" values="0.3;1;0.3" dur="2s" begin="0.6s" repeatCount="indefinite" />
|
|
||||||
</circle>
|
|
||||||
<circle cx="140" cy="184" r="4">
|
|
||||||
<animate attributeName="opacity" values="0.3;1;0.3" dur="2s" begin="1.2s" repeatCount="indefinite" />
|
|
||||||
</circle>
|
|
||||||
</g>
|
|
||||||
|
|
||||||
<path d="M160 120V152V184" stroke="var(--color-primary-6, #165dff)" strokeWidth="2" strokeDasharray="4 4" opacity="0.6">
|
|
||||||
<animate attributeName="stroke-dashoffset" from="16" to="0" dur="1s" repeatCount="indefinite" />
|
|
||||||
</path>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
|
||||||
<Typography.Title heading={2} style={{ color: 'white', marginTop: 0, marginBottom: 12 }}>
|
<Typography.Title heading={2} style={{ color: 'white', marginTop: 0, marginBottom: 12 }}>
|
||||||
{t('auth.bannerTitle')}
|
{t('auth.bannerTitle')}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { Table, Button, Space, Message, Typography, Tag } from '@arco-design/web-react'
|
import { Table, Button, Space, Message, Typography, Tag } from '@arco-design/web-react'
|
||||||
import { IconCopy, IconDownload, IconRefresh } from '@arco-design/web-react/icon'
|
import { IconCopy, IconDownload, IconRefresh } from '../../components/icons'
|
||||||
|
|
||||||
const { Text } = Typography
|
const { Text } = Typography
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
} from '@arco-design/web-react'
|
} from '@arco-design/web-react'
|
||||||
import {
|
import {
|
||||||
IconPlus, IconDelete, IconDesktop, IconCloudDownload, IconEdit, IconMore,
|
IconPlus, IconDelete, IconDesktop, IconCloudDownload, IconEdit, IconMore,
|
||||||
} from '@arco-design/web-react/icon'
|
} from '../../components/icons'
|
||||||
import type { NodeSummary } from '../../types/nodes'
|
import type { NodeSummary } from '../../types/nodes'
|
||||||
import { listNodes, deleteNode, updateNode, rotateNodeToken } from '../../services/nodes'
|
import { listNodes, deleteNode, updateNode, rotateNodeToken } from '../../services/nodes'
|
||||||
import { fetchSystemInfo } from '../../services/system'
|
import { fetchSystemInfo } from '../../services/system'
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { Typography, Button, Space, Collapse, Spin, Message, Tag } from '@arco-design/web-react'
|
import { Typography, Button, Space, Collapse, Spin, Message, Tag } from '@arco-design/web-react'
|
||||||
import { IconCopy, IconRefresh } from '@arco-design/web-react/icon'
|
import { IconCopy, IconRefresh } from '../../../components/icons'
|
||||||
import { fetchScriptPreview } from '../../../services/nodes'
|
import { fetchScriptPreview } from '../../../services/nodes'
|
||||||
import type { InstallTokenResult, InstallMode } from '../../../types/nodes'
|
import type { InstallTokenResult, InstallMode } from '../../../types/nodes'
|
||||||
import { buildAgentDownloadCommand, buildAgentInstallCommand, buildEmbeddedAgentInstallCommand } from '../installCommands'
|
import { buildAgentDownloadCommand, buildAgentInstallCommand, buildEmbeddedAgentInstallCommand } from '../installCommands'
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Button, Card, Grid, Message, Select, Space, Statistic, Table, Tag, Typography } from '@arco-design/web-react'
|
import { Button, Card, Grid, Message, Select, Space, Statistic, Table, Tag, Typography } from '@arco-design/web-react'
|
||||||
import { IconDownload, IconRefresh } from '@arco-design/web-react/icon'
|
import { IconDownload, IconRefresh } from '../../components/icons'
|
||||||
import { useCallback, useEffect, useState } from 'react'
|
import { useCallback, useEffect, useState } from 'react'
|
||||||
import { downloadComplianceCSV, fetchComplianceReport } from '../../services/reports'
|
import { downloadComplianceCSV, fetchComplianceReport } from '../../services/reports'
|
||||||
import type { ComplianceReport, ComplianceRisk, ComplianceTaskRow } from '../../types/reports'
|
import type { ComplianceReport, ComplianceRisk, ComplianceTaskRow } from '../../types/reports'
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import { formatBytes } from '../../utils/format'
|
|||||||
import type { StorageConnectionTestResult, StorageTargetDetail, StorageTargetPayload, StorageTargetSummary } from '../../types/storage-targets'
|
import type { StorageConnectionTestResult, StorageTargetDetail, StorageTargetPayload, StorageTargetSummary } from '../../types/storage-targets'
|
||||||
import { getStorageTargetTypeLabel } from '../../components/storage-targets/field-config'
|
import { getStorageTargetTypeLabel } from '../../components/storage-targets/field-config'
|
||||||
import { StorageTargetFormDrawer } from '../../components/storage-targets/StorageTargetFormDrawer'
|
import { StorageTargetFormDrawer } from '../../components/storage-targets/StorageTargetFormDrawer'
|
||||||
|
import { StorageTargetName } from '../../components/storage-targets/StorageTargetName'
|
||||||
|
|
||||||
function resolveErrorMessage(error: unknown) {
|
function resolveErrorMessage(error: unknown) {
|
||||||
if (axios.isAxiosError(error)) {
|
if (axios.isAxiosError(error)) {
|
||||||
@@ -224,7 +225,7 @@ export function StorageTargetsPage() {
|
|||||||
<Space size="large" align="start" style={{ marginBottom: 16, width: '100%', justifyContent: 'space-between' }}>
|
<Space size="large" align="start" style={{ marginBottom: 16, width: '100%', justifyContent: 'space-between' }}>
|
||||||
<div>
|
<div>
|
||||||
<Typography.Title heading={6} style={{ marginBottom: 4 }}>
|
<Typography.Title heading={6} style={{ marginBottom: 4 }}>
|
||||||
{target.starred ? '★ ' : ''}{target.name}
|
<StorageTargetName name={target.name} starred={target.starred} />
|
||||||
</Typography.Title>
|
</Typography.Title>
|
||||||
<Space>
|
<Space>
|
||||||
{getStorageTargetTypeLabel(target.type) && <Tag color="arcoblue" bordered>{getStorageTargetTypeLabel(target.type)}</Tag>}
|
{getStorageTargetTypeLabel(target.type) && <Tag color="arcoblue" bordered>{getStorageTargetTypeLabel(target.type)}</Tag>}
|
||||||
|
|||||||
Reference in New Issue
Block a user