Copilot commented on code in PR #9931:
URL: https://github.com/apache/gravitino/pull/9931#discussion_r2785666008
##########
web-v2/web/src/app/jobs/page.js:
##########
@@ -326,38 +326,25 @@ export default function JobsPage() {
loading={jobDetailLoading}
onClose={onClose}
open={openDetailJob}
+ width={560}
>
- <>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Job ID</div>
- <span className='break-words
text-base'>{currentJob?.jobId}</span>
- </div>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Template Name</div>
- <span className='break-words
text-base'>{currentJob?.jobTemplateName}</span>
- </div>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Status</div>
- <span className='break-words text-base'>
- {<Tag color={getStatusColor(currentJob?.status ||
'')}>{currentJob?.status}</Tag>}
- </span>
- </div>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Details</div>
- <div className='flex justify-between'>
- <span className='text-sm'>Creator: </span>
- <span className='text-sm'>{currentJob?.audit?.creator}</span>
- </div>
- <div className='flex justify-between'>
- <span className='text-sm'>Created At: </span>
- <span
className='text-sm'>{formatToDateTime(currentJob?.audit?.createTime)}</span>
- </div>
- <div className='flex justify-between'>
- <span className='text-sm'>Updated At: </span>
- <span
className='text-sm'>{formatToDateTime(currentJob?.audit?.lastModifiedTime)}</span>
- </div>
- </div>
- </>
+ <Title level={5} className='mb-2'>
+ Basic Information
+ </Title>
+ <Descriptions column={1} bordered size='small'>
+ <Descriptions.Item label='Job
ID'>{currentJob?.jobId}</Descriptions.Item>
+ <Descriptions.Item label='Template
Name'>{currentJob?.jobTemplateName}</Descriptions.Item>
+ <Descriptions.Item label='Status'>
+ <Tag color={getStatusColor(currentJob?.status ||
'')}>{currentJob?.status}</Tag>
+ </Descriptions.Item>
+ <Descriptions.Item label='Creator'>{currentJob?.audit?.creator
|| '-'}</Descriptions.Item>
+ <Descriptions.Item label='Created At'>
+ {formatToDateTime(currentJob?.audit?.createTime)}
+ </Descriptions.Item>
+ <Descriptions.Item label='Updated At'>
+ {formatToDateTime(currentJob?.audit?.lastModifiedTime) || '-'}
Review Comment:
`formatToDateTime(...) || '-'` won’t ever fall back to `'-'` because
`formatToDateTime` always returns a formatted string (e.g., `dayjs(undefined)`
formats as “now”). This can display an incorrect “Updated At” when
`lastModifiedTime` is missing. Please guard before calling `formatToDateTime`
(or update the util) so missing timestamps render `'-'`.
```suggestion
{currentJob?.audit?.lastModifiedTime
? formatToDateTime(currentJob?.audit?.lastModifiedTime)
: '-'}
```
##########
web-v2/web/src/app/jobTemplates/page.js:
##########
@@ -23,7 +23,7 @@ import { createContext, useContext, useEffect, useMemo,
useState } from 'react'
import dynamic from 'next/dynamic'
import { useRouter, useSearchParams } from 'next/navigation'
import { ExclamationCircleFilled, PlusOutlined } from '@ant-design/icons'
-import { Button, Drawer, Flex, Input, Modal, Space, Spin, Table, Tooltip,
Typography } from 'antd'
+import { Button, Descriptions, Drawer, Empty, Flex, Input, Modal, Spin, Table,
Tooltip, Typography } from 'antd'
Review Comment:
`Empty` is imported from `antd` but not used anywhere in this file. Please
remove the unused import to avoid lint/build failures (and keep imports
accurate).
```suggestion
import { Button, Descriptions, Drawer, Flex, Input, Modal, Spin, Table,
Tooltip, Typography } from 'antd'
```
##########
web-v2/web/src/app/compliance/tags/page.js:
##########
@@ -171,6 +186,11 @@ export default function TagsPage() {
<Icons.Pencil className='size-4' onClick={() =>
handleEditTag(record.name)} />
</Tooltip>
</a>
+ <a>
+ <Tooltip title='View'>
+ <Icons.Eye className='size-4' onClick={() =>
handleViewTag(record)} />
+ </Tooltip>
+ </a>
Review Comment:
These action icons are wrapped in `<a>` tags without an `href`, and the
click handler is on the icon. This makes the actions non-focusable / not
keyboard-accessible for many users. Prefer using an actual `Button` (e.g.,
`type='link'`) or add appropriate button semantics (`role`, `tabIndex`,
keyboard handlers) on the clickable element.
##########
web-v2/web/src/app/jobTemplates/page.js:
##########
@@ -255,183 +255,217 @@ export default function JobTemplatesPage() {
loading={isLoadingDetails}
onClose={onClose}
open={openDetailJobTemplate}
+ width={640}
>
- <>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Template Name</div>
- <span className='break-words
text-base'>{currentJobTemplate?.name}</span>
- </div>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Job Type</div>
- <span className='break-words
text-base'>{currentJobTemplate?.jobType}</span>
- </div>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Executable</div>
- <span className='break-words
text-base'>{currentJobTemplate?.executable}</span>
- </div>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Comment</div>
- <span className='break-words
text-base'>{currentJobTemplate?.comment || '-'}</span>
- </div>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Arguments</div>
- <span className='break-words text-base'>
- {currentJobTemplate?.arguments.length === 1
- ? currentJobTemplate?.arguments[0]
- : currentJobTemplate?.arguments.length
- ? currentJobTemplate?.arguments.join(', ')
- : '-'}
- </span>
- </div>
- <div className='my-4'>
- <div className='mb-1 text-sm text-slate-400'>Environment
Variable(s)</div>
- <Space.Compact className='max-h-80 w-full overflow-auto'>
- <Space.Compact direction='vertical' className='w-1/2
divide-y border-gray-100'>
- <span className='bg-gray-100 p-1'>Env Var Name</span>
- {currentJobTemplate?.environments
- ?
Object.keys(currentJobTemplate?.environments).map(envName => (
- <span key={envName} className='truncate p-1'
title={envName}>
- {envName}
- </span>
- ))
- : null}
- </Space.Compact>
- <Space.Compact direction='vertical' className='w-1/2
divide-y border-gray-100'>
- <span className='bg-gray-100 p-1'>Env Var Value</span>
- {currentJobTemplate?.environments
- ?
Object.values(currentJobTemplate?.environments).map(envValue => (
- <span key={envValue} className='truncate p-1'
title={envValue}>
- {envValue || '-'}
- </span>
- ))
- : null}
- </Space.Compact>
- </Space.Compact>
- </div>
- <div className='my-4'>
- <div className='mb-1 text-sm text-slate-400'>Custom
Fields</div>
- <Space.Compact className='max-h-80 w-full overflow-auto'>
- <Space.Compact direction='vertical' className='w-1/2
divide-y border-gray-100'>
- <span className='bg-gray-100 p-1'>Key</span>
- {currentJobTemplate?.customFields
- ?
Object.keys(currentJobTemplate?.customFields).map(field => (
- <span key={field} className='truncate p-1'
title={field}>
- {field}
- </span>
- ))
- : null}
- </Space.Compact>
- <Space.Compact direction='vertical' className='w-1/2
divide-y border-gray-100'>
- <span className='bg-gray-100 p-1'>Value</span>
- {currentJobTemplate?.customFields
- ?
Object.values(currentJobTemplate?.customFields).map(value => (
- <span key={value} className='truncate p-1'
title={value}>
- {value || '-'}
- </span>
- ))
- : null}
- </Space.Compact>
- </Space.Compact>
- </div>
- {currentJobTemplate?.jobType === 'shell' && (
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Script(s)</div>
- {currentJobTemplate?.scripts &&
currentJobTemplate.scripts.length > 0 ? (
- currentJobTemplate.scripts.map((script, index) => (
- <span key={index} className='mb-2 block break-words
last:mb-0'>
- {script}
- </span>
- ))
- ) : (
- <span>-</span>
- )}
- </div>
- )}
+ <Title level={5} className='mb-2'>
+ Basic Information
+ </Title>
+ <Descriptions column={1} bordered size='small'>
+ <Descriptions.Item label='Template
Name'>{currentJobTemplate?.name}</Descriptions.Item>
+ <Descriptions.Item label='Job
Type'>{currentJobTemplate?.jobType}</Descriptions.Item>
+ <Descriptions.Item
label='Executable'>{currentJobTemplate?.executable}</Descriptions.Item>
+ <Descriptions.Item label='Comment'>{currentJobTemplate?.comment
|| '-'}</Descriptions.Item>
{currentJobTemplate?.jobType === 'spark' && (
- <>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Class Name</div>
- <span className='break-words
text-base'>{currentJobTemplate?.className}</span>
- </div>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Jars</div>
- {currentJobTemplate?.jars &&
currentJobTemplate.jars.length > 0 ? (
- currentJobTemplate.jars.map((jar, index) => (
- <span key={index} className='mb-2 block break-words
last:mb-0'>
- {jar}
- </span>
- ))
- ) : (
- <span>-</span>
- )}
- </div>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Files</div>
- {currentJobTemplate?.files &&
currentJobTemplate.files.length > 0 ? (
- currentJobTemplate.files.map((file, index) => (
- <span key={index} className='mb-2 block break-words
last:mb-0'>
- {file}
- </span>
- ))
- ) : (
- <span>-</span>
- )}
- </div>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Archives</div>
- {currentJobTemplate?.archives &&
currentJobTemplate.archives.length > 0 ? (
- currentJobTemplate.archives.map((archive, index) => (
+ <Descriptions.Item label='Class
Name'>{currentJobTemplate?.className || '-'}</Descriptions.Item>
+ )}
+ <Descriptions.Item label='Arguments'>
+ {currentJobTemplate?.arguments?.length === 1
+ ? currentJobTemplate?.arguments[0]
+ : currentJobTemplate?.arguments?.length
+ ? currentJobTemplate?.arguments.join(', ')
+ : '-'}
+ </Descriptions.Item>
+ {currentJobTemplate?.jobType === 'shell' && (
+ <Descriptions.Item label='Script(s)'>
+ {currentJobTemplate?.scripts &&
currentJobTemplate.scripts.length > 0
+ ? currentJobTemplate.scripts.map((script, index) => (
<span key={index} className='mb-2 block break-words
last:mb-0'>
- {archive}
+ {script}
</span>
))
- ) : (
- <span>-</span>
- )}
- </div>
- <div className='my-4'>
- <div className='mb-1 text-sm
text-slate-400'>Config(s)</div>
- <Space.Compact className='max-h-80 w-full overflow-auto'>
- <Space.Compact direction='vertical' className='w-1/2
divide-y border-gray-100'>
- <span className='bg-gray-100 p-1'>Config Name</span>
- {currentJobTemplate?.configs
- ?
Object.keys(currentJobTemplate?.configs).map(configName => (
- <span key={configName} className='truncate p-1'
title={configName}>
- {configName}
- </span>
- ))
- : null}
- </Space.Compact>
- <Space.Compact direction='vertical' className='w-1/2
divide-y border-gray-100'>
- <span className='bg-gray-100 p-1'>Config Value</span>
- {currentJobTemplate?.configs
- ?
Object.values(currentJobTemplate?.configs).map(configValue => (
- <span key={configValue} className='truncate p-1'
title={configValue}>
- {configValue || '-'}
- </span>
- ))
- : null}
- </Space.Compact>
- </Space.Compact>
- </div>
+ : '-'}
+ </Descriptions.Item>
+ )}
+ {currentJobTemplate?.jobType === 'spark' && (
+ <>
+ <Descriptions.Item label='Class
Name'>{currentJobTemplate?.className || '-'}</Descriptions.Item>
</>
)}
Review Comment:
`Class Name` is rendered twice for Spark job templates (once as a single
`Descriptions.Item`, then again inside the later `jobType === 'spark'` block).
This will duplicate the field in the UI; please keep only one of these blocks
(or replace the second with the other Spark-specific fields you intended).
```suggestion
```
##########
web-v2/web/src/app/compliance/policies/page.js:
##########
@@ -281,91 +285,108 @@ export default function PoliciesPage() {
loading={detailsLoading}
onClose={onClose}
open={openPolicy}
+ width={640}
>
- <>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Policy Name</div>
- <span className='break-words
text-base'>{currentPolicy?.name}</span>
- </div>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Enabled</div>
- <span className='break-words text-base'>
- <Switch checked={currentPolicy?.enabled} disabled size='small'
/>
- </span>
- </div>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Policy Type</div>
- <span className='break-words
text-base'>{currentPolicy?.policyType}</span>
- </div>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Supported Object
Types</div>
- <span className='break-words text-base'>
- {currentPolicy?.content?.supportedObjectTypes.length === 1
- ? currentPolicy?.content?.supportedObjectTypes[0]
- : currentPolicy?.content?.supportedObjectTypes.length
- ? currentPolicy?.content?.supportedObjectTypes.join(', ')
- : '-'}
- </span>
- </div>
- <div className='my-4'>
- <div className='mb-1 text-sm text-slate-400'>Rule(s)</div>
- <Space.Compact className='max-h-80 w-full overflow-auto'>
- <Space.Compact direction='vertical' className='w-1/2 divide-y
border-gray-100'>
- <span className='bg-gray-100 p-1'>Rule Name</span>
- {currentPolicy?.content?.customRules
- ?
Object.keys(currentPolicy?.content?.customRules).map(rule => (
- <span key={rule} className='truncate p-1' title={rule}>
- {rule}
- </span>
- ))
- : null}
- </Space.Compact>
- <Space.Compact direction='vertical' className='w-1/2 divide-y
border-gray-100'>
- <span className='bg-gray-100 p-1'>Rule Content</span>
- {currentPolicy?.content?.customRules
- ?
Object.values(currentPolicy?.content?.customRules).map(ruleContent => (
- <span key={ruleContent} className='truncate p-1'
title={ruleContent}>
- {ruleContent || '-'}
- </span>
- ))
- : null}
- </Space.Compact>
- </Space.Compact>
- </div>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Comment</div>
- <span className='break-words text-base'>{currentPolicy?.comment
|| '-'}</span>
- </div>
- <div className='my-4'>
- <div className='mb-1 text-sm text-slate-400'>Properties</div>
- {currentPolicy?.content?.properties &&
Object.keys(currentPolicy?.content?.properties).length > 0 ? (
- <Space.Compact className='max-h-80 w-full overflow-auto'>
- <Space.Compact direction='vertical' className='w-1/2
divide-y border-gray-100'>
- <span className='bg-gray-100 p-1'>Key</span>
- {currentPolicy?.content?.properties
- ?
Object.keys(currentPolicy?.content?.properties).map(key => (
- <span key={key} className='truncate p-1' title={key}>
- {key}
- </span>
- ))
- : null}
- </Space.Compact>
- <Space.Compact direction='vertical' className='w-1/2
divide-y border-gray-100'>
- <span className='bg-gray-100 p-1'>Value</span>
- {currentPolicy?.content?.properties
- ?
Object.values(currentPolicy?.content?.properties).map(value => (
- <span key={value} className='truncate p-1'
title={value}>
- {value || '-'}
- </span>
- ))
- : null}
- </Space.Compact>
- </Space.Compact>
- ) : (
- <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
- )}
- </div>
- </>
+ <Title level={5} className='mb-2'>
+ Basic Information
+ </Title>
+ <Descriptions column={1} bordered size='small'>
+ <Descriptions.Item label='Policy
Name'>{currentPolicy?.name}</Descriptions.Item>
+ <Descriptions.Item label='Enabled'>
+ <Switch checked={currentPolicy?.enabled} disabled size='small' />
+ </Descriptions.Item>
+ <Descriptions.Item label='Policy
Type'>{currentPolicy?.policyType}</Descriptions.Item>
+ <Descriptions.Item label='Supported Object Types'>
+ {currentPolicy?.content?.supportedObjectTypes?.length === 1
+ ? currentPolicy?.content?.supportedObjectTypes[0]
+ : currentPolicy?.content?.supportedObjectTypes?.length
+ ? currentPolicy?.content?.supportedObjectTypes.join(', ')
+ : '-'}
+ </Descriptions.Item>
+ <Descriptions.Item label='Comment'>{currentPolicy?.comment ||
'-'}</Descriptions.Item>
+ <Descriptions.Item label='Creator'>{currentPolicy?.audit?.creator
|| '-'}</Descriptions.Item>
+ <Descriptions.Item label='Created At'>
+ {formatToDateTime(currentPolicy?.audit?.createTime)}
+ </Descriptions.Item>
+ <Descriptions.Item label='Last Modified At'>
+ {formatToDateTime(currentPolicy?.audit?.lastModifiedTime) || '-'}
Review Comment:
`formatToDateTime(...) || '-'` won’t ever fall back to `'-'` because
`formatToDateTime` always returns a formatted string (e.g., `dayjs(undefined)`
formats as “now”). This can display an incorrect “Last Modified At” when
`lastModifiedTime` is missing. Please guard before calling `formatToDateTime`
(or update the util) so missing timestamps render `'-'`.
```suggestion
{currentPolicy?.audit?.createTime
? formatToDateTime(currentPolicy.audit.createTime)
: '-'}
</Descriptions.Item>
<Descriptions.Item label='Last Modified At'>
{currentPolicy?.audit?.lastModifiedTime
? formatToDateTime(currentPolicy.audit.lastModifiedTime)
: '-'}
```
##########
web-v2/web/src/app/jobTemplates/page.js:
##########
@@ -255,183 +255,217 @@ export default function JobTemplatesPage() {
loading={isLoadingDetails}
onClose={onClose}
open={openDetailJobTemplate}
+ width={640}
>
- <>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Template Name</div>
- <span className='break-words
text-base'>{currentJobTemplate?.name}</span>
- </div>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Job Type</div>
- <span className='break-words
text-base'>{currentJobTemplate?.jobType}</span>
- </div>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Executable</div>
- <span className='break-words
text-base'>{currentJobTemplate?.executable}</span>
- </div>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Comment</div>
- <span className='break-words
text-base'>{currentJobTemplate?.comment || '-'}</span>
- </div>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Arguments</div>
- <span className='break-words text-base'>
- {currentJobTemplate?.arguments.length === 1
- ? currentJobTemplate?.arguments[0]
- : currentJobTemplate?.arguments.length
- ? currentJobTemplate?.arguments.join(', ')
- : '-'}
- </span>
- </div>
- <div className='my-4'>
- <div className='mb-1 text-sm text-slate-400'>Environment
Variable(s)</div>
- <Space.Compact className='max-h-80 w-full overflow-auto'>
- <Space.Compact direction='vertical' className='w-1/2
divide-y border-gray-100'>
- <span className='bg-gray-100 p-1'>Env Var Name</span>
- {currentJobTemplate?.environments
- ?
Object.keys(currentJobTemplate?.environments).map(envName => (
- <span key={envName} className='truncate p-1'
title={envName}>
- {envName}
- </span>
- ))
- : null}
- </Space.Compact>
- <Space.Compact direction='vertical' className='w-1/2
divide-y border-gray-100'>
- <span className='bg-gray-100 p-1'>Env Var Value</span>
- {currentJobTemplate?.environments
- ?
Object.values(currentJobTemplate?.environments).map(envValue => (
- <span key={envValue} className='truncate p-1'
title={envValue}>
- {envValue || '-'}
- </span>
- ))
- : null}
- </Space.Compact>
- </Space.Compact>
- </div>
- <div className='my-4'>
- <div className='mb-1 text-sm text-slate-400'>Custom
Fields</div>
- <Space.Compact className='max-h-80 w-full overflow-auto'>
- <Space.Compact direction='vertical' className='w-1/2
divide-y border-gray-100'>
- <span className='bg-gray-100 p-1'>Key</span>
- {currentJobTemplate?.customFields
- ?
Object.keys(currentJobTemplate?.customFields).map(field => (
- <span key={field} className='truncate p-1'
title={field}>
- {field}
- </span>
- ))
- : null}
- </Space.Compact>
- <Space.Compact direction='vertical' className='w-1/2
divide-y border-gray-100'>
- <span className='bg-gray-100 p-1'>Value</span>
- {currentJobTemplate?.customFields
- ?
Object.values(currentJobTemplate?.customFields).map(value => (
- <span key={value} className='truncate p-1'
title={value}>
- {value || '-'}
- </span>
- ))
- : null}
- </Space.Compact>
- </Space.Compact>
- </div>
- {currentJobTemplate?.jobType === 'shell' && (
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Script(s)</div>
- {currentJobTemplate?.scripts &&
currentJobTemplate.scripts.length > 0 ? (
- currentJobTemplate.scripts.map((script, index) => (
- <span key={index} className='mb-2 block break-words
last:mb-0'>
- {script}
- </span>
- ))
- ) : (
- <span>-</span>
- )}
- </div>
- )}
+ <Title level={5} className='mb-2'>
+ Basic Information
+ </Title>
+ <Descriptions column={1} bordered size='small'>
+ <Descriptions.Item label='Template
Name'>{currentJobTemplate?.name}</Descriptions.Item>
+ <Descriptions.Item label='Job
Type'>{currentJobTemplate?.jobType}</Descriptions.Item>
+ <Descriptions.Item
label='Executable'>{currentJobTemplate?.executable}</Descriptions.Item>
+ <Descriptions.Item label='Comment'>{currentJobTemplate?.comment
|| '-'}</Descriptions.Item>
{currentJobTemplate?.jobType === 'spark' && (
- <>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Class Name</div>
- <span className='break-words
text-base'>{currentJobTemplate?.className}</span>
- </div>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Jars</div>
- {currentJobTemplate?.jars &&
currentJobTemplate.jars.length > 0 ? (
- currentJobTemplate.jars.map((jar, index) => (
- <span key={index} className='mb-2 block break-words
last:mb-0'>
- {jar}
- </span>
- ))
- ) : (
- <span>-</span>
- )}
- </div>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Files</div>
- {currentJobTemplate?.files &&
currentJobTemplate.files.length > 0 ? (
- currentJobTemplate.files.map((file, index) => (
- <span key={index} className='mb-2 block break-words
last:mb-0'>
- {file}
- </span>
- ))
- ) : (
- <span>-</span>
- )}
- </div>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Archives</div>
- {currentJobTemplate?.archives &&
currentJobTemplate.archives.length > 0 ? (
- currentJobTemplate.archives.map((archive, index) => (
+ <Descriptions.Item label='Class
Name'>{currentJobTemplate?.className || '-'}</Descriptions.Item>
+ )}
+ <Descriptions.Item label='Arguments'>
+ {currentJobTemplate?.arguments?.length === 1
+ ? currentJobTemplate?.arguments[0]
+ : currentJobTemplate?.arguments?.length
+ ? currentJobTemplate?.arguments.join(', ')
+ : '-'}
+ </Descriptions.Item>
+ {currentJobTemplate?.jobType === 'shell' && (
+ <Descriptions.Item label='Script(s)'>
+ {currentJobTemplate?.scripts &&
currentJobTemplate.scripts.length > 0
+ ? currentJobTemplate.scripts.map((script, index) => (
<span key={index} className='mb-2 block break-words
last:mb-0'>
- {archive}
+ {script}
</span>
))
- ) : (
- <span>-</span>
- )}
- </div>
- <div className='my-4'>
- <div className='mb-1 text-sm
text-slate-400'>Config(s)</div>
- <Space.Compact className='max-h-80 w-full overflow-auto'>
- <Space.Compact direction='vertical' className='w-1/2
divide-y border-gray-100'>
- <span className='bg-gray-100 p-1'>Config Name</span>
- {currentJobTemplate?.configs
- ?
Object.keys(currentJobTemplate?.configs).map(configName => (
- <span key={configName} className='truncate p-1'
title={configName}>
- {configName}
- </span>
- ))
- : null}
- </Space.Compact>
- <Space.Compact direction='vertical' className='w-1/2
divide-y border-gray-100'>
- <span className='bg-gray-100 p-1'>Config Value</span>
- {currentJobTemplate?.configs
- ?
Object.values(currentJobTemplate?.configs).map(configValue => (
- <span key={configValue} className='truncate p-1'
title={configValue}>
- {configValue || '-'}
- </span>
- ))
- : null}
- </Space.Compact>
- </Space.Compact>
- </div>
+ : '-'}
+ </Descriptions.Item>
+ )}
+ {currentJobTemplate?.jobType === 'spark' && (
+ <>
+ <Descriptions.Item label='Class
Name'>{currentJobTemplate?.className || '-'}</Descriptions.Item>
</>
)}
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Details</div>
- <div className='flex justify-between'>
- <span className='text-sm'>Creator: </span>
- <span
className='text-sm'>{currentJobTemplate?.audit?.creator}</span>
- </div>
- <div className='flex justify-between'>
- <span className='text-sm'>Created At: </span>
- <span
className='text-sm'>{formatToDateTime(currentJobTemplate?.audit?.createTime)}</span>
- </div>
- <div className='flex justify-between'>
- <span className='text-sm'>Updated At: </span>
- <span
className='text-sm'>{formatToDateTime(currentJobTemplate?.audit?.lastModifiedTime)}</span>
- </div>
- </div>
- </>
+ </Descriptions>
+ <Title level={5} className='mt-4 mb-2'>
+ Environment Variable(s)
+ </Title>
+ <Table
+ size='small'
+ pagination={false}
+ rowKey='key'
+ dataSource={
+ currentJobTemplate?.environments &&
Object.keys(currentJobTemplate.environments).length > 0
+ ? Object.entries(currentJobTemplate.environments).map(([key,
value]) => ({
+ key,
+ value
+ }))
+ : []
+ }
+ columns={[
+ {
+ title: 'Env Var Name',
+ dataIndex: 'key',
+ key: 'key',
+ ellipsis: true
+ },
+ {
+ title: 'Env Var Value',
+ dataIndex: 'value',
+ key: 'value',
+ ellipsis: true,
+ render: value => value || '-'
+ }
+ ]}
+ />
+ <Title level={5} className='mt-4 mb-2'>
+ Custom Fields
+ </Title>
+ <Table
+ size='small'
+ pagination={false}
+ rowKey='key'
+ dataSource={
+ currentJobTemplate?.customFields &&
Object.keys(currentJobTemplate.customFields).length > 0
+ ? Object.entries(currentJobTemplate.customFields).map(([key,
value]) => ({
+ key,
+ value
+ }))
+ : []
+ }
+ columns={[
+ {
+ title: 'Key',
+ dataIndex: 'key',
+ key: 'key',
+ ellipsis: true
+ },
+ {
+ title: 'Value',
+ dataIndex: 'value',
+ key: 'value',
+ ellipsis: true,
+ render: value => value || '-'
+ }
+ ]}
+ />
+ {currentJobTemplate?.jobType === 'spark' && (
+ <>
+ <Title level={5} className='mt-4 mb-2'>
+ Jars
+ </Title>
+ <Table
+ size='small'
+ pagination={false}
+ rowKey='value'
+ dataSource={
+ currentJobTemplate?.jars && currentJobTemplate.jars.length
> 0
+ ? currentJobTemplate.jars.map(value => ({ value }))
+ : []
+ }
+ columns={[
+ {
+ title: 'Jar',
+ dataIndex: 'value',
+ key: 'value',
+ ellipsis: true
+ }
+ ]}
+ />
+ <Title level={5} className='mt-4 mb-2'>
+ Files
+ </Title>
+ <Table
+ size='small'
+ pagination={false}
+ rowKey='value'
+ dataSource={
+ currentJobTemplate?.files &&
currentJobTemplate.files.length > 0
+ ? currentJobTemplate.files.map(value => ({ value }))
+ : []
+ }
+ columns={[
+ {
+ title: 'File',
+ dataIndex: 'value',
+ key: 'value',
+ ellipsis: true
+ }
+ ]}
+ />
+ <Title level={5} className='mt-4 mb-2'>
+ Archives
+ </Title>
+ <Table
+ size='small'
+ pagination={false}
+ rowKey='value'
+ dataSource={
+ currentJobTemplate?.archives &&
currentJobTemplate.archives.length > 0
+ ? currentJobTemplate.archives.map(value => ({ value }))
+ : []
+ }
+ columns={[
+ {
+ title: 'Archive',
+ dataIndex: 'value',
+ key: 'value',
+ ellipsis: true
+ }
+ ]}
+ />
+ <Title level={5} className='mt-4 mb-2'>
+ Config(s)
+ </Title>
+ <Table
+ size='small'
+ pagination={false}
+ rowKey='key'
+ dataSource={
+ currentJobTemplate?.configs &&
Object.keys(currentJobTemplate.configs).length > 0
+ ? Object.entries(currentJobTemplate.configs).map(([key,
value]) => ({
+ key,
+ value
+ }))
+ : []
+ }
+ columns={[
+ {
+ title: 'Config Name',
+ dataIndex: 'key',
+ key: 'key',
+ ellipsis: true
+ },
+ {
+ title: 'Config Value',
+ dataIndex: 'value',
+ key: 'value',
+ ellipsis: true,
+ render: value => value || '-'
+ }
+ ]}
+ />
+ </>
+ )}
+ <div className='my-4'>
+ <Typography.Title level={5} className='mb-2'>
+ Details
+ </Typography.Title>
+ <Descriptions size='small' bordered column={1} labelStyle={{
width: 180 }}>
+ <Descriptions.Item
label='Creator'>{currentJobTemplate?.audit?.creator || '-'}</Descriptions.Item>
+ <Descriptions.Item label='Created At'>
+ {formatToDateTime(currentJobTemplate?.audit?.createTime)}
+ </Descriptions.Item>
+ <Descriptions.Item label='Updated At'>
+
{formatToDateTime(currentJobTemplate?.audit?.lastModifiedTime) || '-'}
Review Comment:
`formatToDateTime(...) || '-'` won’t ever fall back to `'-'` because
`formatToDateTime` always returns a formatted string (e.g., `dayjs(undefined)`
formats as “now”). This can display an incorrect “Updated At” when
`lastModifiedTime` is missing. Please guard before calling `formatToDateTime`
(or update the util) so missing timestamps render `'-'`.
```suggestion
{currentJobTemplate?.audit?.createTime
? formatToDateTime(currentJobTemplate.audit.createTime)
: '-'}
</Descriptions.Item>
<Descriptions.Item label='Updated At'>
{currentJobTemplate?.audit?.lastModifiedTime
?
formatToDateTime(currentJobTemplate.audit.lastModifiedTime)
: '-'}
```
##########
web-v2/web/src/app/jobTemplates/page.js:
##########
@@ -255,183 +255,217 @@ export default function JobTemplatesPage() {
loading={isLoadingDetails}
onClose={onClose}
open={openDetailJobTemplate}
+ width={640}
>
- <>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Template Name</div>
- <span className='break-words
text-base'>{currentJobTemplate?.name}</span>
- </div>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Job Type</div>
- <span className='break-words
text-base'>{currentJobTemplate?.jobType}</span>
- </div>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Executable</div>
- <span className='break-words
text-base'>{currentJobTemplate?.executable}</span>
- </div>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Comment</div>
- <span className='break-words
text-base'>{currentJobTemplate?.comment || '-'}</span>
- </div>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Arguments</div>
- <span className='break-words text-base'>
- {currentJobTemplate?.arguments.length === 1
- ? currentJobTemplate?.arguments[0]
- : currentJobTemplate?.arguments.length
- ? currentJobTemplate?.arguments.join(', ')
- : '-'}
- </span>
- </div>
- <div className='my-4'>
- <div className='mb-1 text-sm text-slate-400'>Environment
Variable(s)</div>
- <Space.Compact className='max-h-80 w-full overflow-auto'>
- <Space.Compact direction='vertical' className='w-1/2
divide-y border-gray-100'>
- <span className='bg-gray-100 p-1'>Env Var Name</span>
- {currentJobTemplate?.environments
- ?
Object.keys(currentJobTemplate?.environments).map(envName => (
- <span key={envName} className='truncate p-1'
title={envName}>
- {envName}
- </span>
- ))
- : null}
- </Space.Compact>
- <Space.Compact direction='vertical' className='w-1/2
divide-y border-gray-100'>
- <span className='bg-gray-100 p-1'>Env Var Value</span>
- {currentJobTemplate?.environments
- ?
Object.values(currentJobTemplate?.environments).map(envValue => (
- <span key={envValue} className='truncate p-1'
title={envValue}>
- {envValue || '-'}
- </span>
- ))
- : null}
- </Space.Compact>
- </Space.Compact>
- </div>
- <div className='my-4'>
- <div className='mb-1 text-sm text-slate-400'>Custom
Fields</div>
- <Space.Compact className='max-h-80 w-full overflow-auto'>
- <Space.Compact direction='vertical' className='w-1/2
divide-y border-gray-100'>
- <span className='bg-gray-100 p-1'>Key</span>
- {currentJobTemplate?.customFields
- ?
Object.keys(currentJobTemplate?.customFields).map(field => (
- <span key={field} className='truncate p-1'
title={field}>
- {field}
- </span>
- ))
- : null}
- </Space.Compact>
- <Space.Compact direction='vertical' className='w-1/2
divide-y border-gray-100'>
- <span className='bg-gray-100 p-1'>Value</span>
- {currentJobTemplate?.customFields
- ?
Object.values(currentJobTemplate?.customFields).map(value => (
- <span key={value} className='truncate p-1'
title={value}>
- {value || '-'}
- </span>
- ))
- : null}
- </Space.Compact>
- </Space.Compact>
- </div>
- {currentJobTemplate?.jobType === 'shell' && (
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Script(s)</div>
- {currentJobTemplate?.scripts &&
currentJobTemplate.scripts.length > 0 ? (
- currentJobTemplate.scripts.map((script, index) => (
- <span key={index} className='mb-2 block break-words
last:mb-0'>
- {script}
- </span>
- ))
- ) : (
- <span>-</span>
- )}
- </div>
- )}
+ <Title level={5} className='mb-2'>
+ Basic Information
+ </Title>
+ <Descriptions column={1} bordered size='small'>
+ <Descriptions.Item label='Template
Name'>{currentJobTemplate?.name}</Descriptions.Item>
+ <Descriptions.Item label='Job
Type'>{currentJobTemplate?.jobType}</Descriptions.Item>
+ <Descriptions.Item
label='Executable'>{currentJobTemplate?.executable}</Descriptions.Item>
+ <Descriptions.Item label='Comment'>{currentJobTemplate?.comment
|| '-'}</Descriptions.Item>
{currentJobTemplate?.jobType === 'spark' && (
- <>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Class Name</div>
- <span className='break-words
text-base'>{currentJobTemplate?.className}</span>
- </div>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Jars</div>
- {currentJobTemplate?.jars &&
currentJobTemplate.jars.length > 0 ? (
- currentJobTemplate.jars.map((jar, index) => (
- <span key={index} className='mb-2 block break-words
last:mb-0'>
- {jar}
- </span>
- ))
- ) : (
- <span>-</span>
- )}
- </div>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Files</div>
- {currentJobTemplate?.files &&
currentJobTemplate.files.length > 0 ? (
- currentJobTemplate.files.map((file, index) => (
- <span key={index} className='mb-2 block break-words
last:mb-0'>
- {file}
- </span>
- ))
- ) : (
- <span>-</span>
- )}
- </div>
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Archives</div>
- {currentJobTemplate?.archives &&
currentJobTemplate.archives.length > 0 ? (
- currentJobTemplate.archives.map((archive, index) => (
+ <Descriptions.Item label='Class
Name'>{currentJobTemplate?.className || '-'}</Descriptions.Item>
+ )}
+ <Descriptions.Item label='Arguments'>
+ {currentJobTemplate?.arguments?.length === 1
+ ? currentJobTemplate?.arguments[0]
+ : currentJobTemplate?.arguments?.length
+ ? currentJobTemplate?.arguments.join(', ')
+ : '-'}
+ </Descriptions.Item>
+ {currentJobTemplate?.jobType === 'shell' && (
+ <Descriptions.Item label='Script(s)'>
+ {currentJobTemplate?.scripts &&
currentJobTemplate.scripts.length > 0
+ ? currentJobTemplate.scripts.map((script, index) => (
<span key={index} className='mb-2 block break-words
last:mb-0'>
- {archive}
+ {script}
</span>
))
- ) : (
- <span>-</span>
- )}
- </div>
- <div className='my-4'>
- <div className='mb-1 text-sm
text-slate-400'>Config(s)</div>
- <Space.Compact className='max-h-80 w-full overflow-auto'>
- <Space.Compact direction='vertical' className='w-1/2
divide-y border-gray-100'>
- <span className='bg-gray-100 p-1'>Config Name</span>
- {currentJobTemplate?.configs
- ?
Object.keys(currentJobTemplate?.configs).map(configName => (
- <span key={configName} className='truncate p-1'
title={configName}>
- {configName}
- </span>
- ))
- : null}
- </Space.Compact>
- <Space.Compact direction='vertical' className='w-1/2
divide-y border-gray-100'>
- <span className='bg-gray-100 p-1'>Config Value</span>
- {currentJobTemplate?.configs
- ?
Object.values(currentJobTemplate?.configs).map(configValue => (
- <span key={configValue} className='truncate p-1'
title={configValue}>
- {configValue || '-'}
- </span>
- ))
- : null}
- </Space.Compact>
- </Space.Compact>
- </div>
+ : '-'}
+ </Descriptions.Item>
+ )}
+ {currentJobTemplate?.jobType === 'spark' && (
+ <>
+ <Descriptions.Item label='Class
Name'>{currentJobTemplate?.className || '-'}</Descriptions.Item>
</>
)}
- <div className='my-4'>
- <div className='text-sm text-slate-400'>Details</div>
- <div className='flex justify-between'>
- <span className='text-sm'>Creator: </span>
- <span
className='text-sm'>{currentJobTemplate?.audit?.creator}</span>
- </div>
- <div className='flex justify-between'>
- <span className='text-sm'>Created At: </span>
- <span
className='text-sm'>{formatToDateTime(currentJobTemplate?.audit?.createTime)}</span>
- </div>
- <div className='flex justify-between'>
- <span className='text-sm'>Updated At: </span>
- <span
className='text-sm'>{formatToDateTime(currentJobTemplate?.audit?.lastModifiedTime)}</span>
- </div>
- </div>
- </>
+ </Descriptions>
+ <Title level={5} className='mt-4 mb-2'>
+ Environment Variable(s)
+ </Title>
+ <Table
+ size='small'
+ pagination={false}
+ rowKey='key'
+ dataSource={
+ currentJobTemplate?.environments &&
Object.keys(currentJobTemplate.environments).length > 0
+ ? Object.entries(currentJobTemplate.environments).map(([key,
value]) => ({
+ key,
+ value
+ }))
+ : []
+ }
+ columns={[
+ {
+ title: 'Env Var Name',
+ dataIndex: 'key',
+ key: 'key',
+ ellipsis: true
+ },
+ {
+ title: 'Env Var Value',
+ dataIndex: 'value',
+ key: 'value',
+ ellipsis: true,
+ render: value => value || '-'
+ }
+ ]}
+ />
+ <Title level={5} className='mt-4 mb-2'>
+ Custom Fields
+ </Title>
+ <Table
+ size='small'
+ pagination={false}
+ rowKey='key'
+ dataSource={
+ currentJobTemplate?.customFields &&
Object.keys(currentJobTemplate.customFields).length > 0
+ ? Object.entries(currentJobTemplate.customFields).map(([key,
value]) => ({
+ key,
+ value
+ }))
+ : []
+ }
+ columns={[
+ {
+ title: 'Key',
+ dataIndex: 'key',
+ key: 'key',
+ ellipsis: true
+ },
+ {
+ title: 'Value',
+ dataIndex: 'value',
+ key: 'value',
+ ellipsis: true,
+ render: value => value || '-'
+ }
+ ]}
+ />
+ {currentJobTemplate?.jobType === 'spark' && (
+ <>
+ <Title level={5} className='mt-4 mb-2'>
+ Jars
+ </Title>
+ <Table
+ size='small'
+ pagination={false}
+ rowKey='value'
+ dataSource={
+ currentJobTemplate?.jars && currentJobTemplate.jars.length
> 0
+ ? currentJobTemplate.jars.map(value => ({ value }))
+ : []
+ }
+ columns={[
+ {
+ title: 'Jar',
+ dataIndex: 'value',
+ key: 'value',
+ ellipsis: true
+ }
+ ]}
+ />
+ <Title level={5} className='mt-4 mb-2'>
+ Files
+ </Title>
+ <Table
+ size='small'
+ pagination={false}
+ rowKey='value'
+ dataSource={
+ currentJobTemplate?.files &&
currentJobTemplate.files.length > 0
+ ? currentJobTemplate.files.map(value => ({ value }))
+ : []
+ }
+ columns={[
+ {
+ title: 'File',
+ dataIndex: 'value',
+ key: 'value',
+ ellipsis: true
+ }
+ ]}
+ />
+ <Title level={5} className='mt-4 mb-2'>
+ Archives
+ </Title>
+ <Table
+ size='small'
+ pagination={false}
+ rowKey='value'
+ dataSource={
+ currentJobTemplate?.archives &&
currentJobTemplate.archives.length > 0
+ ? currentJobTemplate.archives.map(value => ({ value }))
+ : []
+ }
+ columns={[
+ {
+ title: 'Archive',
+ dataIndex: 'value',
+ key: 'value',
+ ellipsis: true
+ }
+ ]}
+ />
+ <Title level={5} className='mt-4 mb-2'>
+ Config(s)
+ </Title>
+ <Table
+ size='small'
+ pagination={false}
+ rowKey='key'
+ dataSource={
+ currentJobTemplate?.configs &&
Object.keys(currentJobTemplate.configs).length > 0
+ ? Object.entries(currentJobTemplate.configs).map(([key,
value]) => ({
+ key,
+ value
+ }))
+ : []
+ }
+ columns={[
+ {
+ title: 'Config Name',
+ dataIndex: 'key',
+ key: 'key',
+ ellipsis: true
+ },
+ {
+ title: 'Config Value',
+ dataIndex: 'value',
+ key: 'value',
+ ellipsis: true,
+ render: value => value || '-'
+ }
+ ]}
+ />
+ </>
+ )}
+ <div className='my-4'>
+ <Typography.Title level={5} className='mb-2'>
+ Details
+ </Typography.Title>
+ <Descriptions size='small' bordered column={1} labelStyle={{
width: 180 }}>
Review Comment:
The PR title/linked issue (#9807) calls out adding “Associated roles” for
Job Templates as well, but this details drawer currently doesn’t render an
associated roles section (unlike Tags/Policies). Either add the Job Template
associated roles UI here (if supported by the roles API) or adjust the PR
title/scope to match what’s implemented.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]