mirror of
https://github.com/langgenius/dify.git
synced 2026-02-24 18:05:11 +00:00
Compare commits
6 Commits
41e2812349
...
feature/ta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a0aa8cdb45 | ||
|
|
ae8618877b | ||
|
|
1c55602445 | ||
|
|
a3f1220d23 | ||
|
|
d62e16b9bb | ||
|
|
13f2a43ccc |
@@ -16,6 +16,7 @@ import { Theme } from '@/types/app'
|
|||||||
import SVGRenderer from '../svg-gallery' // Assumes svg-gallery.tsx is in /base directory
|
import SVGRenderer from '../svg-gallery' // Assumes svg-gallery.tsx is in /base directory
|
||||||
|
|
||||||
const Flowchart = dynamic(() => import('@/app/components/base/mermaid'), { ssr: false })
|
const Flowchart = dynamic(() => import('@/app/components/base/mermaid'), { ssr: false })
|
||||||
|
const QuadrantMatrix = dynamic(() => import('@/app/components/base/quadrant-matrix'), { ssr: false })
|
||||||
|
|
||||||
// Available language https://github.com/react-syntax-highlighter/react-syntax-highlighter/blob/master/AVAILABLE_LANGUAGES_HLJS.MD
|
// Available language https://github.com/react-syntax-highlighter/react-syntax-highlighter/blob/master/AVAILABLE_LANGUAGES_HLJS.MD
|
||||||
const capitalizationLanguageNameMap: Record<string, string> = {
|
const capitalizationLanguageNameMap: Record<string, string> = {
|
||||||
@@ -40,6 +41,7 @@ const capitalizationLanguageNameMap: Record<string, string> = {
|
|||||||
latex: 'Latex',
|
latex: 'Latex',
|
||||||
svg: 'SVG',
|
svg: 'SVG',
|
||||||
abc: 'ABC',
|
abc: 'ABC',
|
||||||
|
quadrant: 'Quadrant',
|
||||||
}
|
}
|
||||||
const getCorrectCapitalizationLanguageName = (language: string) => {
|
const getCorrectCapitalizationLanguageName = (language: string) => {
|
||||||
if (!language)
|
if (!language)
|
||||||
@@ -409,6 +411,12 @@ const CodeBlock: any = memo(({ inline, className, children = '', ...props }: any
|
|||||||
<MarkdownMusic children={content} />
|
<MarkdownMusic children={content} />
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
)
|
)
|
||||||
|
case 'quadrant':
|
||||||
|
return (
|
||||||
|
<ErrorBoundary>
|
||||||
|
<QuadrantMatrix content={content} />
|
||||||
|
</ErrorBoundary>
|
||||||
|
)
|
||||||
default:
|
default:
|
||||||
return (
|
return (
|
||||||
<SyntaxHighlighter
|
<SyntaxHighlighter
|
||||||
|
|||||||
153
web/app/components/base/quadrant-matrix/index.tsx
Normal file
153
web/app/components/base/quadrant-matrix/index.tsx
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
'use client'
|
||||||
|
import type { FC } from 'react'
|
||||||
|
import type { QuadrantData } from './types'
|
||||||
|
import { RiExpandDiagonalLine } from '@remixicon/react'
|
||||||
|
import { useCallback, useMemo, useState } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import ActionButton from '@/app/components/base/action-button'
|
||||||
|
import FullScreenModal from '@/app/components/base/fullscreen-modal'
|
||||||
|
import QuadrantCard from './quadrant-card'
|
||||||
|
import { isValidQuadrantData, QUADRANT_CONFIGS } from './types'
|
||||||
|
|
||||||
|
type QuadrantMatrixProps = {
|
||||||
|
content: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const QuadrantMatrix: FC<QuadrantMatrixProps> = ({ content }) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const [isExpanded, setIsExpanded] = useState(false)
|
||||||
|
|
||||||
|
const parsedData = useMemo<QuadrantData | null>(() => {
|
||||||
|
try {
|
||||||
|
const trimmed = content.trim()
|
||||||
|
const data = JSON.parse(trimmed)
|
||||||
|
|
||||||
|
if (!isValidQuadrantData(data))
|
||||||
|
return null
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}, [content])
|
||||||
|
|
||||||
|
const handleExpand = useCallback(() => {
|
||||||
|
setIsExpanded(true)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const handleClose = useCallback(() => {
|
||||||
|
setIsExpanded(false)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
if (!parsedData) {
|
||||||
|
return (
|
||||||
|
<div className="flex items-center justify-center rounded-xl bg-components-panel-bg-blur p-8">
|
||||||
|
<div className="text-center text-text-secondary">
|
||||||
|
<div className="system-md-semibold mb-2">{t('quadrantMatrix.invalidData', { ns: 'app' })}</div>
|
||||||
|
<div className="text-sm text-text-tertiary">
|
||||||
|
{t('quadrantMatrix.invalidDataDesc', { ns: 'app' })}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const totalTasks
|
||||||
|
= parsedData.q1.length
|
||||||
|
+ parsedData.q2.length
|
||||||
|
+ parsedData.q3.length
|
||||||
|
+ parsedData.q4.length
|
||||||
|
|
||||||
|
// Shared grid content component
|
||||||
|
const renderGrid = (expanded: boolean) => (
|
||||||
|
<div className="grid grid-cols-2 gap-3">
|
||||||
|
{/* Row 1: Q1 (Do First), Q2 (Schedule) */}
|
||||||
|
<QuadrantCard
|
||||||
|
config={QUADRANT_CONFIGS.q1}
|
||||||
|
tasks={parsedData.q1}
|
||||||
|
expanded={expanded}
|
||||||
|
/>
|
||||||
|
<QuadrantCard
|
||||||
|
config={QUADRANT_CONFIGS.q2}
|
||||||
|
tasks={parsedData.q2}
|
||||||
|
expanded={expanded}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Row 2: Q3 (Delegate), Q4 (Don't Do) */}
|
||||||
|
<QuadrantCard
|
||||||
|
config={QUADRANT_CONFIGS.q3}
|
||||||
|
tasks={parsedData.q3}
|
||||||
|
expanded={expanded}
|
||||||
|
/>
|
||||||
|
<QuadrantCard
|
||||||
|
config={QUADRANT_CONFIGS.q4}
|
||||||
|
tasks={parsedData.q4}
|
||||||
|
expanded={expanded}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="w-full overflow-hidden rounded-xl bg-components-panel-bg-blur p-4">
|
||||||
|
{/* Header */}
|
||||||
|
<div className="mb-4 flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<div className="system-md-semibold text-text-primary">
|
||||||
|
{t('quadrantMatrix.title', { ns: 'app' })}
|
||||||
|
</div>
|
||||||
|
<div className="text-xs text-text-tertiary">
|
||||||
|
{t('quadrantMatrix.taskCount', { ns: 'app', count: totalTasks })}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* Legend + Expand Button */}
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="flex items-center gap-3 text-[11px] text-text-quaternary">
|
||||||
|
<span>{t('quadrantMatrix.legend.importance', { ns: 'app' })}</span>
|
||||||
|
<span>{t('quadrantMatrix.legend.urgency', { ns: 'app' })}</span>
|
||||||
|
</div>
|
||||||
|
<ActionButton onClick={handleExpand}>
|
||||||
|
<RiExpandDiagonalLine className="h-4 w-4" />
|
||||||
|
</ActionButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 2x2 Grid */}
|
||||||
|
{renderGrid(false)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Fullscreen Modal */}
|
||||||
|
<FullScreenModal
|
||||||
|
open={isExpanded}
|
||||||
|
onClose={handleClose}
|
||||||
|
closable
|
||||||
|
>
|
||||||
|
<div className="flex h-full flex-col p-6">
|
||||||
|
{/* Modal Header */}
|
||||||
|
<div className="mb-6 flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<div className="text-xl font-semibold text-text-primary">
|
||||||
|
{t('quadrantMatrix.title', { ns: 'app' })}
|
||||||
|
</div>
|
||||||
|
<div className="text-sm text-text-tertiary">
|
||||||
|
{t('quadrantMatrix.taskCount', { ns: 'app', count: totalTasks })}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-3 text-sm text-text-quaternary">
|
||||||
|
<span>{t('quadrantMatrix.legend.importance', { ns: 'app' })}</span>
|
||||||
|
<span>{t('quadrantMatrix.legend.urgency', { ns: 'app' })}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Expanded Grid */}
|
||||||
|
<div className="min-h-0 flex-1">
|
||||||
|
{renderGrid(true)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</FullScreenModal>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default QuadrantMatrix
|
||||||
102
web/app/components/base/quadrant-matrix/quadrant-card.tsx
Normal file
102
web/app/components/base/quadrant-matrix/quadrant-card.tsx
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
'use client'
|
||||||
|
import type { FC } from 'react'
|
||||||
|
import type { QuadrantConfig, Task } from './types'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { cn } from '@/utils/classnames'
|
||||||
|
import TaskItem from './task-item'
|
||||||
|
|
||||||
|
type QuadrantCardProps = {
|
||||||
|
config: QuadrantConfig
|
||||||
|
tasks: Task[]
|
||||||
|
expanded?: boolean
|
||||||
|
maxDisplay?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const QuadrantCard: FC<QuadrantCardProps> = ({
|
||||||
|
config,
|
||||||
|
tasks,
|
||||||
|
expanded = false,
|
||||||
|
maxDisplay = 3,
|
||||||
|
}) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const { number, titleKey, subtitleKey, bgClass, borderClass, titleClass } = config
|
||||||
|
const displayLimit = expanded ? Infinity : maxDisplay
|
||||||
|
const displayTasks = tasks.slice(0, displayLimit)
|
||||||
|
const remainingCount = Math.max(0, tasks.length - displayLimit)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
'flex min-w-0 flex-col rounded-xl border p-3',
|
||||||
|
bgClass,
|
||||||
|
borderClass,
|
||||||
|
expanded ? 'min-h-[280px]' : 'min-h-[200px]',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{/* Header with numbered circle */}
|
||||||
|
<div className="mb-2 shrink-0">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
{/* Numbered circle */}
|
||||||
|
<span className={cn(
|
||||||
|
'flex h-5 w-5 items-center justify-center rounded-full border text-xs font-semibold',
|
||||||
|
borderClass,
|
||||||
|
titleClass,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{number}
|
||||||
|
</span>
|
||||||
|
<span className={cn('system-sm-semibold', titleClass)}>{t(titleKey, { ns: 'app' })}</span>
|
||||||
|
{tasks.length > 0 && (
|
||||||
|
<span className="bg-components-badge-bg-gray rounded-full px-1.5 py-0.5 text-[10px] font-medium text-text-tertiary">
|
||||||
|
{tasks.length}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="text-[11px] text-text-tertiary">{t(subtitleKey, { ns: 'app' })}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Task List */}
|
||||||
|
<div className={cn(
|
||||||
|
'flex min-h-0 flex-1 flex-col gap-2',
|
||||||
|
expanded && 'overflow-y-auto',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{displayTasks.length > 0
|
||||||
|
? (
|
||||||
|
displayTasks.map((task) => {
|
||||||
|
const taskKey = [
|
||||||
|
task.name,
|
||||||
|
task.deadline ?? 'no-deadline',
|
||||||
|
task.importance_score,
|
||||||
|
task.urgency_score,
|
||||||
|
task.description ?? '',
|
||||||
|
task.action_advice ?? '',
|
||||||
|
].join('|')
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TaskItem
|
||||||
|
key={taskKey}
|
||||||
|
task={task}
|
||||||
|
expanded={expanded}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
: (
|
||||||
|
<div className="flex flex-1 items-center justify-center text-xs text-text-quaternary">
|
||||||
|
{t('quadrantMatrix.noTasks', { ns: 'app' })}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* More indicator (only in non-expanded mode) */}
|
||||||
|
{!expanded && remainingCount > 0 && (
|
||||||
|
<div className="mt-2 shrink-0 text-center text-[11px] text-text-tertiary">
|
||||||
|
{t('quadrantMatrix.more', { ns: 'app', count: remainingCount })}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default QuadrantCard
|
||||||
88
web/app/components/base/quadrant-matrix/task-item.tsx
Normal file
88
web/app/components/base/quadrant-matrix/task-item.tsx
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
'use client'
|
||||||
|
import type { FC } from 'react'
|
||||||
|
import type { Task } from './types'
|
||||||
|
import { RiCalendarLine } from '@remixicon/react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { cn } from '@/utils/classnames'
|
||||||
|
|
||||||
|
type TaskItemProps = {
|
||||||
|
task: Task
|
||||||
|
expanded?: boolean
|
||||||
|
showScores?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const TaskItem: FC<TaskItemProps> = ({ task, expanded = false, showScores = true }) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const { name, description, deadline, importance_score, urgency_score, action_advice } = task
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="group min-w-0 rounded-lg bg-components-panel-bg p-2.5 shadow-xs transition-all hover:shadow-sm">
|
||||||
|
{/* Header: Task Name + Scores */}
|
||||||
|
<div className="flex items-start justify-between gap-2">
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
'system-sm-medium min-w-0 flex-1 text-text-primary',
|
||||||
|
!expanded && 'truncate',
|
||||||
|
)}
|
||||||
|
title={name}
|
||||||
|
>
|
||||||
|
{name}
|
||||||
|
</div>
|
||||||
|
{showScores && (
|
||||||
|
<div className="flex shrink-0 items-center gap-1 text-[10px] font-medium">
|
||||||
|
<span className="text-text-accent">
|
||||||
|
I:
|
||||||
|
{importance_score}
|
||||||
|
</span>
|
||||||
|
<span className="text-text-warning">
|
||||||
|
U:
|
||||||
|
{urgency_score}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Description */}
|
||||||
|
{description && (
|
||||||
|
<div className={cn(
|
||||||
|
'mt-1 text-xs text-text-tertiary',
|
||||||
|
!expanded && 'line-clamp-2',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{description}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Deadline Badge */}
|
||||||
|
{deadline && (
|
||||||
|
<div className="mt-1.5">
|
||||||
|
<span className="bg-components-badge-bg-gray inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-[10px] text-text-tertiary">
|
||||||
|
<RiCalendarLine className="h-3 w-3" />
|
||||||
|
<span>
|
||||||
|
{t('quadrantMatrix.deadline', { ns: 'app' })}
|
||||||
|
{' '}
|
||||||
|
{deadline}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Action Advice */}
|
||||||
|
{action_advice && (
|
||||||
|
<div className="mt-2 border-t border-divider-subtle pt-2">
|
||||||
|
<p
|
||||||
|
className={cn(
|
||||||
|
'text-xs italic text-text-quaternary',
|
||||||
|
!expanded && 'line-clamp-2',
|
||||||
|
)}
|
||||||
|
title={!expanded ? action_advice : undefined}
|
||||||
|
>
|
||||||
|
{action_advice}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TaskItem
|
||||||
92
web/app/components/base/quadrant-matrix/types.ts
Normal file
92
web/app/components/base/quadrant-matrix/types.ts
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
/**
|
||||||
|
* Type definitions for Eisenhower Matrix (Task Quadrant) visualization
|
||||||
|
*/
|
||||||
|
import type { I18nKeysWithPrefix } from '@/types/i18n'
|
||||||
|
|
||||||
|
export type Task = {
|
||||||
|
name: string
|
||||||
|
description?: string
|
||||||
|
deadline?: string // YYYY-MM-DD format
|
||||||
|
importance_score: number // 0-100, based on goal alignment and long-term value
|
||||||
|
urgency_score: number // 0-100, based on deadline pressure and delay penalty
|
||||||
|
action_advice?: string // Suggested action for this task
|
||||||
|
}
|
||||||
|
|
||||||
|
export type QuadrantData = {
|
||||||
|
q1: Task[] // Urgent & Important - Do First
|
||||||
|
q2: Task[] // Not Urgent & Important - Schedule
|
||||||
|
q3: Task[] // Urgent & Not Important - Delegate
|
||||||
|
q4: Task[] // Not Urgent & Not Important - Don't Do
|
||||||
|
}
|
||||||
|
|
||||||
|
type QuadrantKeyBase = I18nKeysWithPrefix<'app', 'quadrantMatrix.q'>
|
||||||
|
type QuadrantTitleKey = Extract<QuadrantKeyBase, `${string}.title`>
|
||||||
|
type QuadrantSubtitleKey = Extract<QuadrantKeyBase, `${string}.subtitle`>
|
||||||
|
|
||||||
|
export type QuadrantConfig = {
|
||||||
|
key: 'q1' | 'q2' | 'q3' | 'q4'
|
||||||
|
number: number
|
||||||
|
titleKey: QuadrantTitleKey // i18n key for title
|
||||||
|
subtitleKey: QuadrantSubtitleKey // i18n key for subtitle
|
||||||
|
bgClass: string
|
||||||
|
borderClass: string
|
||||||
|
titleClass: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Layout based on Eisenhower Matrix:
|
||||||
|
// Q1 (Do First) - top-left, Q2 (Schedule) - top-right
|
||||||
|
// Q3 (Delegate) - bottom-left, Q4 (Don't Do) - bottom-right
|
||||||
|
export const QUADRANT_CONFIGS: Record<string, QuadrantConfig> = {
|
||||||
|
q1: {
|
||||||
|
key: 'q1',
|
||||||
|
number: 1,
|
||||||
|
titleKey: 'quadrantMatrix.q1.title',
|
||||||
|
subtitleKey: 'quadrantMatrix.q1.subtitle',
|
||||||
|
bgClass: 'bg-state-destructive-hover',
|
||||||
|
borderClass: 'border-state-destructive-border',
|
||||||
|
titleClass: 'text-text-destructive',
|
||||||
|
},
|
||||||
|
q2: {
|
||||||
|
key: 'q2',
|
||||||
|
number: 2,
|
||||||
|
titleKey: 'quadrantMatrix.q2.title',
|
||||||
|
subtitleKey: 'quadrantMatrix.q2.subtitle',
|
||||||
|
bgClass: 'bg-state-accent-hover',
|
||||||
|
borderClass: 'border-state-accent-border',
|
||||||
|
titleClass: 'text-text-accent',
|
||||||
|
},
|
||||||
|
q3: {
|
||||||
|
key: 'q3',
|
||||||
|
number: 3,
|
||||||
|
titleKey: 'quadrantMatrix.q3.title',
|
||||||
|
subtitleKey: 'quadrantMatrix.q3.subtitle',
|
||||||
|
bgClass: 'bg-state-warning-hover',
|
||||||
|
borderClass: 'border-state-warning-border',
|
||||||
|
titleClass: 'text-text-warning',
|
||||||
|
},
|
||||||
|
q4: {
|
||||||
|
key: 'q4',
|
||||||
|
number: 4,
|
||||||
|
titleKey: 'quadrantMatrix.q4.title',
|
||||||
|
subtitleKey: 'quadrantMatrix.q4.subtitle',
|
||||||
|
bgClass: 'bg-components-panel-on-panel-item-bg',
|
||||||
|
borderClass: 'border-divider-regular',
|
||||||
|
titleClass: 'text-text-tertiary',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates if the data structure matches QuadrantData interface
|
||||||
|
*/
|
||||||
|
export function isValidQuadrantData(data: unknown): data is QuadrantData {
|
||||||
|
if (typeof data !== 'object' || data === null)
|
||||||
|
return false
|
||||||
|
|
||||||
|
const d = data as Record<string, unknown>
|
||||||
|
return (
|
||||||
|
Array.isArray(d.q1)
|
||||||
|
&& Array.isArray(d.q2)
|
||||||
|
&& Array.isArray(d.q3)
|
||||||
|
&& Array.isArray(d.q4)
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -196,6 +196,24 @@
|
|||||||
"publishApp.notSet": "Not set",
|
"publishApp.notSet": "Not set",
|
||||||
"publishApp.notSetDesc": "Currently nobody can access the web app. Please set permissions.",
|
"publishApp.notSetDesc": "Currently nobody can access the web app. Please set permissions.",
|
||||||
"publishApp.title": "Who can access web app",
|
"publishApp.title": "Who can access web app",
|
||||||
|
"quadrantMatrix.deadline": "DDL:",
|
||||||
|
"quadrantMatrix.invalidData": "Invalid Quadrant Data",
|
||||||
|
"quadrantMatrix.invalidDataDesc": "Expected JSON format with q1, q2, q3, q4 arrays",
|
||||||
|
"quadrantMatrix.legend.importance": "I = Importance",
|
||||||
|
"quadrantMatrix.legend.urgency": "U = Urgency",
|
||||||
|
"quadrantMatrix.more": "+{{count}} more",
|
||||||
|
"quadrantMatrix.noTasks": "No tasks",
|
||||||
|
"quadrantMatrix.q1.subtitle": "Urgent & Important",
|
||||||
|
"quadrantMatrix.q1.title": "Do First",
|
||||||
|
"quadrantMatrix.q2.subtitle": "Important & Not Urgent",
|
||||||
|
"quadrantMatrix.q2.title": "Schedule",
|
||||||
|
"quadrantMatrix.q3.subtitle": "Urgent & Not Important",
|
||||||
|
"quadrantMatrix.q3.title": "Delegate",
|
||||||
|
"quadrantMatrix.q4.subtitle": "Not Urgent & Not Important",
|
||||||
|
"quadrantMatrix.q4.title": "Don't Do",
|
||||||
|
"quadrantMatrix.taskCount_one": "{{count}} task prioritized",
|
||||||
|
"quadrantMatrix.taskCount_other": "{{count}} tasks prioritized",
|
||||||
|
"quadrantMatrix.title": "Eisenhower Matrix",
|
||||||
"removeOriginal": "Delete the original app",
|
"removeOriginal": "Delete the original app",
|
||||||
"roadmap": "See our roadmap",
|
"roadmap": "See our roadmap",
|
||||||
"showMyCreatedAppsOnly": "Created by me",
|
"showMyCreatedAppsOnly": "Created by me",
|
||||||
|
|||||||
@@ -196,6 +196,24 @@
|
|||||||
"publishApp.notSet": "未设置",
|
"publishApp.notSet": "未设置",
|
||||||
"publishApp.notSetDesc": "当前任何人都无法访问 Web 应用。请设置访问权限。",
|
"publishApp.notSetDesc": "当前任何人都无法访问 Web 应用。请设置访问权限。",
|
||||||
"publishApp.title": "谁可以访问 web 应用",
|
"publishApp.title": "谁可以访问 web 应用",
|
||||||
|
"quadrantMatrix.deadline": "截止:",
|
||||||
|
"quadrantMatrix.invalidData": "无效的象限数据",
|
||||||
|
"quadrantMatrix.invalidDataDesc": "需要包含 q1, q2, q3, q4 数组的 JSON 格式",
|
||||||
|
"quadrantMatrix.legend.importance": "I = 重要性",
|
||||||
|
"quadrantMatrix.legend.urgency": "U = 紧急性",
|
||||||
|
"quadrantMatrix.more": "+{{count}} 更多",
|
||||||
|
"quadrantMatrix.noTasks": "暂无任务",
|
||||||
|
"quadrantMatrix.q1.subtitle": "紧急且重要",
|
||||||
|
"quadrantMatrix.q1.title": "立即执行",
|
||||||
|
"quadrantMatrix.q2.subtitle": "重要但不紧急",
|
||||||
|
"quadrantMatrix.q2.title": "计划安排",
|
||||||
|
"quadrantMatrix.q3.subtitle": "紧急但不重要",
|
||||||
|
"quadrantMatrix.q3.title": "委派他人",
|
||||||
|
"quadrantMatrix.q4.subtitle": "不紧急也不重要",
|
||||||
|
"quadrantMatrix.q4.title": "不要做",
|
||||||
|
"quadrantMatrix.taskCount_one": "{{count}} 个任务已排序",
|
||||||
|
"quadrantMatrix.taskCount_other": "{{count}} 个任务已排序",
|
||||||
|
"quadrantMatrix.title": "艾森豪威尔矩阵",
|
||||||
"removeOriginal": "删除原应用",
|
"removeOriginal": "删除原应用",
|
||||||
"roadmap": "产品路线图",
|
"roadmap": "产品路线图",
|
||||||
"showMyCreatedAppsOnly": "我创建的",
|
"showMyCreatedAppsOnly": "我创建的",
|
||||||
|
|||||||
Reference in New Issue
Block a user