Update web ui for dependency refactor
This updates the web ui to handle multiple changes per item. It is compatible with the current data output as well as the upcoming API. Change-Id: I536967e51b22b60c8ff7baa46b902a36d1ea44dd
This commit is contained in:
parent
c531adacae
commit
4a7e86f7f6
|
@ -48,22 +48,22 @@ ExternalLink.propTypes = {
|
||||||
children: PropTypes.node,
|
children: PropTypes.node,
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildExternalLink(buildish) {
|
function buildExternalLink(ref) {
|
||||||
/* TODO (felix): What should we show for periodic builds
|
/* TODO (felix): What should we show for periodic builds
|
||||||
here? They don't provide a change, but the ref_url is
|
here? They don't provide a change, but the ref_url is
|
||||||
also not usable */
|
also not usable */
|
||||||
if (buildish.ref_url && buildish.change) {
|
if (ref.ref_url && ref.change) {
|
||||||
return (
|
return (
|
||||||
<ExternalLink target={buildish.ref_url}>
|
<ExternalLink target={ref.ref_url}>
|
||||||
<strong>Change </strong>
|
<strong>Change </strong>
|
||||||
{buildish.change},{buildish.patchset}
|
{ref.change},{ref.patchset}
|
||||||
</ExternalLink>
|
</ExternalLink>
|
||||||
)
|
)
|
||||||
} else if (buildish.ref_url && buildish.newrev) {
|
} else if (ref.ref_url && ref.newrev) {
|
||||||
return (
|
return (
|
||||||
<ExternalLink target={buildish.ref_url}>
|
<ExternalLink target={ref.ref_url}>
|
||||||
<strong>Revision </strong>
|
<strong>Revision </strong>
|
||||||
{buildish.newrev.slice(0, 7)}
|
{ref.newrev.slice(0, 7)}
|
||||||
</ExternalLink>
|
</ExternalLink>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -71,20 +71,20 @@ function buildExternalLink(buildish) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildExternalTableLink(buildish) {
|
function buildExternalTableLink(ref) {
|
||||||
/* TODO (felix): What should we show for periodic builds
|
/* TODO (felix): What should we show for periodic builds
|
||||||
here? They don't provide a change, but the ref_url is
|
here? They don't provide a change, but the ref_url is
|
||||||
also not usable */
|
also not usable */
|
||||||
if (buildish.ref_url && buildish.change) {
|
if (ref.ref_url && ref.change) {
|
||||||
return (
|
return (
|
||||||
<ExternalLink target={buildish.ref_url}>
|
<ExternalLink target={ref.ref_url}>
|
||||||
{buildish.change},{buildish.patchset}
|
{ref.change},{ref.patchset}
|
||||||
</ExternalLink>
|
</ExternalLink>
|
||||||
)
|
)
|
||||||
} else if (buildish.ref_url && buildish.newrev) {
|
} else if (ref.ref_url && ref.newrev) {
|
||||||
return (
|
return (
|
||||||
<ExternalLink target={buildish.ref_url}>
|
<ExternalLink target={ref.ref_url}>
|
||||||
{buildish.newrev.slice(0, 7)}
|
{ref.newrev.slice(0, 7)}
|
||||||
</ExternalLink>
|
</ExternalLink>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -92,6 +92,32 @@ function buildExternalTableLink(buildish) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderRefInfo(ref) {
|
||||||
|
const refinfo = ref.branch ? (
|
||||||
|
<>
|
||||||
|
<strong>Branch </strong> {ref.branch}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<strong>Ref </strong> {ref.ref}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
const oldrev = ref.oldrev ? (
|
||||||
|
<><br/><strong>Old</strong> {ref.oldrev}</>
|
||||||
|
) : ( <></> )
|
||||||
|
const newrev = ref.newrev ? (
|
||||||
|
<><br/><strong>New</strong> {ref.newrev}</>
|
||||||
|
) : ( <></> )
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{refinfo}
|
||||||
|
{oldrev}
|
||||||
|
{newrev}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function IconProperty(props) {
|
function IconProperty(props) {
|
||||||
const { icon, value, WrapElement = 'span' } = props
|
const { icon, value, WrapElement = 'span' } = props
|
||||||
return (
|
return (
|
||||||
|
@ -146,4 +172,4 @@ function setDarkMode(darkMode) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { IconProperty, removeHash, ExternalLink, buildExternalLink, buildExternalTableLink, ConditionalWrapper, resolveDarkMode, setDarkMode }
|
export { IconProperty, removeHash, ExternalLink, buildExternalLink, buildExternalTableLink, renderRefInfo, ConditionalWrapper, resolveDarkMode, setDarkMode }
|
||||||
|
|
|
@ -22,8 +22,6 @@ import {
|
||||||
BookIcon,
|
BookIcon,
|
||||||
BuildIcon,
|
BuildIcon,
|
||||||
CodeBranchIcon,
|
CodeBranchIcon,
|
||||||
CodeIcon,
|
|
||||||
CubeIcon,
|
|
||||||
FileCodeIcon,
|
FileCodeIcon,
|
||||||
FingerprintIcon,
|
FingerprintIcon,
|
||||||
HistoryIcon,
|
HistoryIcon,
|
||||||
|
@ -35,20 +33,36 @@ import {
|
||||||
} from '@patternfly/react-icons'
|
} from '@patternfly/react-icons'
|
||||||
import * as moment from 'moment'
|
import * as moment from 'moment'
|
||||||
import * as moment_tz from 'moment-timezone'
|
import * as moment_tz from 'moment-timezone'
|
||||||
|
import _ from 'lodash'
|
||||||
import 'moment-duration-format'
|
import 'moment-duration-format'
|
||||||
|
|
||||||
import { BuildResultBadge, BuildResultWithIcon } from './Misc'
|
import { BuildResultBadge, BuildResultWithIcon } from './Misc'
|
||||||
import { buildExternalLink, ExternalLink, IconProperty } from '../../Misc'
|
import { buildExternalLink, renderRefInfo, ExternalLink, IconProperty } from '../../Misc'
|
||||||
|
|
||||||
import AutoholdModal from '../autohold/autoholdModal'
|
import AutoholdModal from '../autohold/autoholdModal'
|
||||||
|
|
||||||
|
function getRefs(build) {
|
||||||
|
// This method has a purpose beyond backwards compat: return the
|
||||||
|
// zuul ref for this build first, then the remaining refs.
|
||||||
|
if (!('refs' in build.buildset)) {
|
||||||
|
// Backwards compat
|
||||||
|
return [build]
|
||||||
|
}
|
||||||
|
return [build.ref, ...build.buildset.refs.filter((i) => !_.isEqual(i, build.ref))]
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRef(build) {
|
||||||
|
return 'project' in build ? build : build.ref
|
||||||
|
}
|
||||||
|
|
||||||
function Build({ build, tenant, timezone, user }) {
|
function Build({ build, tenant, timezone, user }) {
|
||||||
const [showAutoholdModal, setShowAutoholdModal] = useState(false)
|
const [showAutoholdModal, setShowAutoholdModal] = useState(false)
|
||||||
const change = build.change ? build.change : ''
|
const buildRef = getRef(build)
|
||||||
const ref = build.change ? '' : build.ref
|
// the change or ref to use for api actions like autohold
|
||||||
const project = build.project
|
const actionRef = buildRef.change ? '' : buildRef.ref
|
||||||
|
const actionChange = buildRef.change ? String(buildRef.change) : ''
|
||||||
|
//const project = build.project
|
||||||
const job_name = build.job_name
|
const job_name = build.job_name
|
||||||
const build_link = buildExternalLink(build)
|
|
||||||
const index_links = build.manifest && build.manifest.index_links
|
const index_links = build.manifest && build.manifest.index_links
|
||||||
const build_log_url = build.log_url ?
|
const build_log_url = build.log_url ?
|
||||||
(index_links ? build.log_url + 'index.html' : build.log_url)
|
(index_links ? build.log_url + 'index.html' : build.log_url)
|
||||||
|
@ -78,7 +92,6 @@ function Build({ build, tenant, timezone, user }) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Title
|
<Title
|
||||||
|
@ -112,38 +125,20 @@ function Build({ build, tenant, timezone, user }) {
|
||||||
<Flex flex={{ lg: 'flex_1' }}>
|
<Flex flex={{ lg: 'flex_1' }}>
|
||||||
<FlexItem>
|
<FlexItem>
|
||||||
<List style={{ listStyle: 'none' }}>
|
<List style={{ listStyle: 'none' }}>
|
||||||
{build_link && (
|
{getRefs(build).map((ref, idx) => (
|
||||||
<IconProperty
|
<IconProperty
|
||||||
|
key={idx}
|
||||||
WrapElement={ListItem}
|
WrapElement={ListItem}
|
||||||
icon={<CodeIcon />}
|
icon={<CodeBranchIcon />}
|
||||||
value={build_link}
|
value={
|
||||||
|
<span>
|
||||||
|
{buildExternalLink(ref)}<br/>
|
||||||
|
<strong>Project </strong> {ref.project}<br/>
|
||||||
|
{renderRefInfo(ref)}
|
||||||
|
</span>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
))}
|
||||||
{/* TODO (felix): Link to project page in Zuul */}
|
|
||||||
<IconProperty
|
|
||||||
WrapElement={ListItem}
|
|
||||||
icon={<CubeIcon />}
|
|
||||||
value={
|
|
||||||
<>
|
|
||||||
<strong>Project </strong> {build.project}
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<IconProperty
|
|
||||||
WrapElement={ListItem}
|
|
||||||
icon={<CodeBranchIcon />}
|
|
||||||
value={
|
|
||||||
build.branch ? (
|
|
||||||
<>
|
|
||||||
<strong>Branch </strong> {build.branch}
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<strong>Ref </strong> {build.ref}
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<IconProperty
|
<IconProperty
|
||||||
WrapElement={ListItem}
|
WrapElement={ListItem}
|
||||||
icon={<StreamIcon />}
|
icon={<StreamIcon />}
|
||||||
|
@ -225,7 +220,7 @@ function Build({ build, tenant, timezone, user }) {
|
||||||
'/builds?job_name=' +
|
'/builds?job_name=' +
|
||||||
build.job_name +
|
build.job_name +
|
||||||
'&project=' +
|
'&project=' +
|
||||||
build.project
|
buildRef.project
|
||||||
}
|
}
|
||||||
title="See previous runs of this job inside current project."
|
title="See previous runs of this job inside current project."
|
||||||
>
|
>
|
||||||
|
@ -277,9 +272,9 @@ function Build({ build, tenant, timezone, user }) {
|
||||||
{<AutoholdModal
|
{<AutoholdModal
|
||||||
showAutoholdModal={showAutoholdModal}
|
showAutoholdModal={showAutoholdModal}
|
||||||
setShowAutoholdModal={setShowAutoholdModal}
|
setShowAutoholdModal={setShowAutoholdModal}
|
||||||
change={String(change)}
|
change={actionChange}
|
||||||
changeRef={ref}
|
changeRef={actionRef}
|
||||||
project={project}
|
project={buildRef.project}
|
||||||
jobName={job_name}
|
jobName={job_name}
|
||||||
/>}
|
/>}
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -50,6 +50,10 @@ import * as moment_tz from 'moment-timezone'
|
||||||
import { BuildResult, BuildResultWithIcon } from './Misc'
|
import { BuildResult, BuildResultWithIcon } from './Misc'
|
||||||
import { buildExternalTableLink, IconProperty } from '../../Misc'
|
import { buildExternalTableLink, IconProperty } from '../../Misc'
|
||||||
|
|
||||||
|
function getRef(build) {
|
||||||
|
return 'project' in build ? build : build.ref
|
||||||
|
}
|
||||||
|
|
||||||
function BuildTable({
|
function BuildTable({
|
||||||
builds,
|
builds,
|
||||||
fetching,
|
fetching,
|
||||||
|
@ -101,7 +105,8 @@ function BuildTable({
|
||||||
]
|
]
|
||||||
|
|
||||||
function createBuildRow(build) {
|
function createBuildRow(build) {
|
||||||
const changeOrRefLink = buildExternalTableLink(build)
|
const ref = getRef(build)
|
||||||
|
const changeOrRefLink = buildExternalTableLink(ref)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// Pass the build's uuid as row id, so we can use it later on in the
|
// Pass the build's uuid as row id, so we can use it later on in the
|
||||||
|
@ -125,10 +130,10 @@ function BuildTable({
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: build.project,
|
title: ref.project,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: build.branch ? build.branch : build.ref,
|
title: ref.branch ? ref.branch : ref.ref,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: build.pipeline,
|
title: build.pipeline,
|
||||||
|
|
|
@ -27,10 +27,8 @@ import {
|
||||||
ModalVariant,
|
ModalVariant,
|
||||||
} from '@patternfly/react-core'
|
} from '@patternfly/react-core'
|
||||||
import {
|
import {
|
||||||
CodeIcon,
|
|
||||||
CodeBranchIcon,
|
CodeBranchIcon,
|
||||||
OutlinedCommentDotsIcon,
|
OutlinedCommentDotsIcon,
|
||||||
CubeIcon,
|
|
||||||
FingerprintIcon,
|
FingerprintIcon,
|
||||||
StreamIcon,
|
StreamIcon,
|
||||||
OutlinedCalendarAltIcon,
|
OutlinedCalendarAltIcon,
|
||||||
|
@ -41,15 +39,19 @@ import * as moment from 'moment'
|
||||||
import * as moment_tz from 'moment-timezone'
|
import * as moment_tz from 'moment-timezone'
|
||||||
import 'moment-duration-format'
|
import 'moment-duration-format'
|
||||||
|
|
||||||
import { buildExternalLink, IconProperty } from '../../Misc'
|
import { buildExternalLink, renderRefInfo, IconProperty } from '../../Misc'
|
||||||
import { BuildResultBadge, BuildResultWithIcon } from './Misc'
|
import { BuildResultBadge, BuildResultWithIcon } from './Misc'
|
||||||
import { enqueue, enqueue_ref } from '../../api'
|
import { enqueue, enqueue_ref } from '../../api'
|
||||||
import { addNotification, addApiError } from '../../actions/notifications'
|
import { addNotification, addApiError } from '../../actions/notifications'
|
||||||
import { ChartModal } from '../charts/ChartModal'
|
import { ChartModal } from '../charts/ChartModal'
|
||||||
import BuildsetGanttChart from '../charts/GanttChart'
|
import BuildsetGanttChart from '../charts/GanttChart'
|
||||||
|
|
||||||
|
function getRefs(buildset) {
|
||||||
|
// For backwards compat: get a list of this items changes.
|
||||||
|
return 'refs' in buildset ? buildset.refs : [buildset]
|
||||||
|
}
|
||||||
|
|
||||||
function Buildset({ buildset, timezone, tenant, user, preferences }) {
|
function Buildset({ buildset, timezone, tenant, user, preferences }) {
|
||||||
const buildset_link = buildExternalLink(buildset)
|
|
||||||
const [isGanttChartModalOpen, setIsGanttChartModalOpen] = useState(false)
|
const [isGanttChartModalOpen, setIsGanttChartModalOpen] = useState(false)
|
||||||
|
|
||||||
function renderBuildTimes() {
|
function renderBuildTimes() {
|
||||||
|
@ -234,32 +236,6 @@ function Buildset({ buildset, timezone, tenant, user, preferences }) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderRefInfo(buildset) {
|
|
||||||
const refinfo = buildset.branch ? (
|
|
||||||
<>
|
|
||||||
<strong>Branch </strong> {buildset.branch}
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<strong>Ref </strong> {buildset.ref}
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
const oldrev = buildset.oldrev ? (
|
|
||||||
<><br/><strong>Old</strong> {buildset.oldrev}</>
|
|
||||||
) : ( <></> )
|
|
||||||
const newrev = buildset.newrev ? (
|
|
||||||
<><br/><strong>New</strong> {buildset.newrev}</>
|
|
||||||
) : ( <></> )
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{refinfo}
|
|
||||||
{oldrev}
|
|
||||||
{newrev}
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Title headingLevel="h2">
|
<Title headingLevel="h2">
|
||||||
|
@ -276,32 +252,20 @@ function Buildset({ buildset, timezone, tenant, user, preferences }) {
|
||||||
<Flex flex={{ default: 'flex_1' }}>
|
<Flex flex={{ default: 'flex_1' }}>
|
||||||
<FlexItem>
|
<FlexItem>
|
||||||
<List style={{ listStyle: 'none' }}>
|
<List style={{ listStyle: 'none' }}>
|
||||||
{/* TODO (felix): It would be cool if we could differentiate
|
{getRefs(buildset).map((ref, idx) => (
|
||||||
between the SVC system (Github, Gitlab, Gerrit), so we could
|
|
||||||
show the respective icon here (GithubIcon, GitlabIcon,
|
|
||||||
GitIcon - AFAIK the Gerrit icon is not very popular among
|
|
||||||
icon frameworks like fontawesome */}
|
|
||||||
{buildset_link && (
|
|
||||||
<IconProperty
|
<IconProperty
|
||||||
WrapElement={ListItem}
|
WrapElement={ListItem}
|
||||||
icon={<CodeIcon />}
|
icon={<CodeBranchIcon />}
|
||||||
value={buildset_link}
|
key={idx}
|
||||||
|
value={
|
||||||
|
<span>
|
||||||
|
{buildExternalLink(ref)}<br/>
|
||||||
|
<strong>Project </strong> {ref.project}<br/>
|
||||||
|
{renderRefInfo(ref)}
|
||||||
|
</span>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
))}
|
||||||
{/* TODO (felix): Link to project page in Zuul */}
|
|
||||||
<IconProperty
|
|
||||||
WrapElement={ListItem}
|
|
||||||
icon={<CubeIcon />}
|
|
||||||
value={
|
|
||||||
<>
|
|
||||||
<strong>Project </strong> {buildset.project}
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<IconProperty
|
|
||||||
WrapElement={ListItem}
|
|
||||||
icon={<CodeBranchIcon />}
|
|
||||||
value={renderRefInfo(buildset)}/>
|
|
||||||
<IconProperty
|
<IconProperty
|
||||||
WrapElement={ListItem}
|
WrapElement={ListItem}
|
||||||
icon={<StreamIcon />}
|
icon={<StreamIcon />}
|
||||||
|
|
|
@ -55,6 +55,10 @@ import * as moment_tz from 'moment-timezone'
|
||||||
import { BuildResult, BuildResultWithIcon } from './Misc'
|
import { BuildResult, BuildResultWithIcon } from './Misc'
|
||||||
import { buildExternalTableLink, IconProperty } from '../../Misc'
|
import { buildExternalTableLink, IconProperty } from '../../Misc'
|
||||||
|
|
||||||
|
function getRef(buildset) {
|
||||||
|
return 'refs' in buildset ? buildset.refs[0] : buildset
|
||||||
|
}
|
||||||
|
|
||||||
function BuildsetTable({
|
function BuildsetTable({
|
||||||
buildsets,
|
buildsets,
|
||||||
fetching,
|
fetching,
|
||||||
|
@ -140,7 +144,8 @@ function BuildsetTable({
|
||||||
]
|
]
|
||||||
|
|
||||||
function createBuildsetRow(buildset) {
|
function createBuildsetRow(buildset) {
|
||||||
const changeOrRefLink = buildExternalTableLink(buildset)
|
const ref = getRef(buildset)
|
||||||
|
const changeOrRefLink = buildExternalTableLink(ref)
|
||||||
|
|
||||||
let duration
|
let duration
|
||||||
if (currentDuration === 'Buildset Duration') {
|
if (currentDuration === 'Buildset Duration') {
|
||||||
|
@ -163,12 +168,12 @@ function BuildsetTable({
|
||||||
<BuildResultWithIcon
|
<BuildResultWithIcon
|
||||||
result={buildset.result}
|
result={buildset.result}
|
||||||
link={`${tenant.linkPrefix}/buildset/${buildset.uuid}`}>
|
link={`${tenant.linkPrefix}/buildset/${buildset.uuid}`}>
|
||||||
{buildset.project}
|
{ref.project}
|
||||||
</BuildResultWithIcon>
|
</BuildResultWithIcon>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: buildset.branch ? buildset.branch : buildset.ref,
|
title: ref.branch ? ref.branch : ref.ref,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: buildset.pipeline,
|
title: buildset.pipeline,
|
||||||
|
|
|
@ -17,7 +17,7 @@ import PropTypes from 'prop-types'
|
||||||
import { Badge } from 'patternfly-react'
|
import { Badge } from 'patternfly-react'
|
||||||
import { Tooltip } from '@patternfly/react-core'
|
import { Tooltip } from '@patternfly/react-core'
|
||||||
|
|
||||||
import Change from './Change'
|
import Item from './Item'
|
||||||
|
|
||||||
|
|
||||||
class ChangeQueue extends React.Component {
|
class ChangeQueue extends React.Component {
|
||||||
|
@ -38,15 +38,15 @@ class ChangeQueue extends React.Component {
|
||||||
shortName = shortName.substr(0, 32) + '...'
|
shortName = shortName.substr(0, 32) + '...'
|
||||||
}
|
}
|
||||||
let changesList = []
|
let changesList = []
|
||||||
queue.heads.forEach((changes, changeIdx) => {
|
queue.heads.forEach((items, itemIdx) => {
|
||||||
changes.forEach((change, idx) => {
|
items.forEach((item, idx) => {
|
||||||
changesList.push(
|
changesList.push(
|
||||||
<Change
|
<Item
|
||||||
change={change}
|
item={item}
|
||||||
queue={queue}
|
queue={queue}
|
||||||
expanded={expanded}
|
expanded={expanded}
|
||||||
pipeline={pipeline}
|
pipeline={pipeline}
|
||||||
key={changeIdx.toString() + idx}
|
key={itemIdx.toString() + idx}
|
||||||
/>)
|
/>)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -37,12 +37,17 @@ import { fetchStatusIfNeeded } from '../../actions/status'
|
||||||
|
|
||||||
import LineAngleImage from '../../images/line-angle.png'
|
import LineAngleImage from '../../images/line-angle.png'
|
||||||
import LineTImage from '../../images/line-t.png'
|
import LineTImage from '../../images/line-t.png'
|
||||||
import ChangePanel from './ChangePanel'
|
import ItemPanel from './ItemPanel'
|
||||||
|
|
||||||
|
function getChange(item) {
|
||||||
|
// For backwards compat: get a representative change for this item
|
||||||
|
// if there is more than one.
|
||||||
|
return 'changes' in item ? item.changes[0] : item
|
||||||
|
}
|
||||||
|
|
||||||
class Change extends React.Component {
|
class Item extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
change: PropTypes.object.isRequired,
|
item: PropTypes.object.isRequired,
|
||||||
queue: PropTypes.object.isRequired,
|
queue: PropTypes.object.isRequired,
|
||||||
expanded: PropTypes.bool.isRequired,
|
expanded: PropTypes.bool.isRequired,
|
||||||
pipeline: PropTypes.object,
|
pipeline: PropTypes.object,
|
||||||
|
@ -59,7 +64,10 @@ class Change extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
dequeueConfirm = () => {
|
dequeueConfirm = () => {
|
||||||
const { tenant, change, pipeline } = this.props
|
const { tenant, item, pipeline } = this.props
|
||||||
|
const change = getChange(item)
|
||||||
|
// Use the first change as a proxy for the item since queue
|
||||||
|
// commands operate on changes
|
||||||
let projectName = change.project
|
let projectName = change.project
|
||||||
let changeId = change.id || 'N/A'
|
let changeId = change.id || 'N/A'
|
||||||
let changeRef = change.ref
|
let changeRef = change.ref
|
||||||
|
@ -90,7 +98,8 @@ class Change extends React.Component {
|
||||||
|
|
||||||
renderDequeueModal() {
|
renderDequeueModal() {
|
||||||
const { showDequeueModal } = this.state
|
const { showDequeueModal } = this.state
|
||||||
const { change } = this.props
|
const { item } = this.props
|
||||||
|
const change = getChange(item)
|
||||||
let projectName = change.project
|
let projectName = change.project
|
||||||
let changeId = change.id || change.ref
|
let changeId = change.id || change.ref
|
||||||
const title = 'You are about to dequeue a change'
|
const title = 'You are about to dequeue a change'
|
||||||
|
@ -111,7 +120,8 @@ class Change extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
promoteConfirm = () => {
|
promoteConfirm = () => {
|
||||||
const { tenant, change, pipeline } = this.props
|
const { tenant, item, pipeline } = this.props
|
||||||
|
const change = getChange(item)
|
||||||
let changeId = change.id || 'NA'
|
let changeId = change.id || 'NA'
|
||||||
this.setState(() => ({ showPromoteModal: false }))
|
this.setState(() => ({ showPromoteModal: false }))
|
||||||
if (changeId !== 'N/A') {
|
if (changeId !== 'N/A') {
|
||||||
|
@ -138,7 +148,8 @@ class Change extends React.Component {
|
||||||
|
|
||||||
renderPromoteModal() {
|
renderPromoteModal() {
|
||||||
const { showPromoteModal } = this.state
|
const { showPromoteModal } = this.state
|
||||||
const { change } = this.props
|
const { item } = this.props
|
||||||
|
const change = getChange(item)
|
||||||
let changeId = change.id || 'N/A'
|
let changeId = change.id || 'N/A'
|
||||||
const title = 'You are about to promote a change'
|
const title = 'You are about to promote a change'
|
||||||
return (
|
return (
|
||||||
|
@ -166,7 +177,7 @@ class Change extends React.Component {
|
||||||
icon={<BanIcon style={{
|
icon={<BanIcon style={{
|
||||||
color: 'var(--pf-global--danger-color--100)',
|
color: 'var(--pf-global--danger-color--100)',
|
||||||
}} />}
|
}} />}
|
||||||
description="Stop all jobs for this change"
|
description="Stop all jobs for this item"
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
this.setState(() => ({ showDequeueModal: true }))
|
this.setState(() => ({ showDequeueModal: true }))
|
||||||
|
@ -177,7 +188,7 @@ class Change extends React.Component {
|
||||||
icon={<AngleDoubleUpIcon style={{
|
icon={<AngleDoubleUpIcon style={{
|
||||||
color: 'var(--pf-global--default-color--200)',
|
color: 'var(--pf-global--default-color--200)',
|
||||||
}} />}
|
}} />}
|
||||||
description="Promote this change to the top of the queue"
|
description="Promote this item to the top of the queue"
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
this.setState(() => ({ showPromoteModal: true }))
|
this.setState(() => ({ showPromoteModal: true }))
|
||||||
|
@ -207,20 +218,19 @@ class Change extends React.Component {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderStatusIcon(item) {
|
||||||
renderStatusIcon(change) {
|
|
||||||
let iconGlyph = 'pficon pficon-ok'
|
let iconGlyph = 'pficon pficon-ok'
|
||||||
let iconTitle = 'Succeeding'
|
let iconTitle = 'Succeeding'
|
||||||
if (change.active !== true) {
|
if (item.active !== true) {
|
||||||
iconGlyph = 'pficon pficon-pending'
|
iconGlyph = 'pficon pficon-pending'
|
||||||
iconTitle = 'Waiting until closer to head of queue to' +
|
iconTitle = 'Waiting until closer to head of queue to' +
|
||||||
' start jobs'
|
' start jobs'
|
||||||
} else if (change.live !== true) {
|
} else if (item.live !== true) {
|
||||||
iconGlyph = 'pficon pficon-info'
|
iconGlyph = 'pficon pficon-info'
|
||||||
iconTitle = 'Dependent change required for testing'
|
iconTitle = 'Dependent item required for testing'
|
||||||
} else if (change.failing_reasons &&
|
} else if (item.failing_reasons &&
|
||||||
change.failing_reasons.length > 0) {
|
item.failing_reasons.length > 0) {
|
||||||
let reason = change.failing_reasons.join(', ')
|
let reason = item.failing_reasons.join(', ')
|
||||||
iconTitle = 'Failing because ' + reason
|
iconTitle = 'Failing because ' + reason
|
||||||
if (reason.match(/merge conflict/)) {
|
if (reason.match(/merge conflict/)) {
|
||||||
iconGlyph = 'pficon pficon-error-circle-o zuul-build-merge-conflict'
|
iconGlyph = 'pficon pficon-error-circle-o zuul-build-merge-conflict'
|
||||||
|
@ -233,9 +243,9 @@ class Change extends React.Component {
|
||||||
className={'zuul-build-status ' + iconGlyph}
|
className={'zuul-build-status ' + iconGlyph}
|
||||||
title={iconTitle} />
|
title={iconTitle} />
|
||||||
)
|
)
|
||||||
if (change.live) {
|
if (item.live) {
|
||||||
return (
|
return (
|
||||||
<Link to={this.props.tenant.linkPrefix + '/status/change/' + change.id}>
|
<Link to={this.props.tenant.linkPrefix + '/status/change/' + getChange(item).id}>
|
||||||
{icon}
|
{icon}
|
||||||
</Link>
|
</Link>
|
||||||
)
|
)
|
||||||
|
@ -244,9 +254,9 @@ class Change extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderLineImg(change, i) {
|
renderLineImg(item, i) {
|
||||||
let image = LineTImage
|
let image = LineTImage
|
||||||
if (change._tree_branches.indexOf(i) === change._tree_branches.length - 1) {
|
if (item._tree_branches.indexOf(i) === item._tree_branches.length - 1) {
|
||||||
// Angle line
|
// Angle line
|
||||||
image = LineAngleImage
|
image = LineAngleImage
|
||||||
}
|
}
|
||||||
|
@ -254,13 +264,13 @@ class Change extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { change, queue, expanded, pipeline, user, tenant } = this.props
|
const { item, queue, expanded, pipeline, user, tenant } = this.props
|
||||||
let row = []
|
let row = []
|
||||||
let adminMenuWidth = 15
|
let adminMenuWidth = 15
|
||||||
let i
|
let i
|
||||||
for (i = 0; i < queue._tree_columns; i++) {
|
for (i = 0; i < queue._tree_columns; i++) {
|
||||||
let className = ''
|
let className = ''
|
||||||
if (i < change._tree.length && change._tree[i] !== null) {
|
if (i < item._tree.length && item._tree[i] !== null) {
|
||||||
if (this.props.preferences.darkMode) {
|
if (this.props.preferences.darkMode) {
|
||||||
className = ' zuul-change-row-line-dark'
|
className = ' zuul-change-row-line-dark'
|
||||||
} else {
|
} else {
|
||||||
|
@ -269,19 +279,19 @@ class Change extends React.Component {
|
||||||
}
|
}
|
||||||
row.push(
|
row.push(
|
||||||
<td key={i} className={'zuul-change-row' + className}>
|
<td key={i} className={'zuul-change-row' + className}>
|
||||||
{i === change._tree_index ? this.renderStatusIcon(change) : ''}
|
{i === item._tree_index ? this.renderStatusIcon(item) : ''}
|
||||||
{change._tree_branches.indexOf(i) !== -1 ? (
|
{item._tree_branches.indexOf(i) !== -1 ? (
|
||||||
this.renderLineImg(change, i)) : ''}
|
this.renderLineImg(item, i)) : ''}
|
||||||
</td>)
|
</td>)
|
||||||
}
|
}
|
||||||
let changeWidth = (user.isAdmin && user.scope.indexOf(tenant.name) !== -1)
|
let itemWidth = (user.isAdmin && user.scope.indexOf(tenant.name) !== -1)
|
||||||
? 360 - adminMenuWidth - 16 * queue._tree_columns
|
? 360 - adminMenuWidth - 16 * queue._tree_columns
|
||||||
: 360 - 16 * queue._tree_columns
|
: 360 - 16 * queue._tree_columns
|
||||||
row.push(
|
row.push(
|
||||||
<td key={i + 1}
|
<td key={i + 1}
|
||||||
className="zuul-change-cell"
|
className="zuul-change-cell"
|
||||||
style={{ width: changeWidth + 'px' }}>
|
style={{ width: itemWidth + 'px' }}>
|
||||||
<ChangePanel change={change} globalExpanded={expanded} pipeline={pipeline} />
|
<ItemPanel item={item} globalExpanded={expanded} pipeline={pipeline} />
|
||||||
</td>
|
</td>
|
||||||
)
|
)
|
||||||
if (user.isAdmin && user.scope.indexOf(tenant.name) !== -1) {
|
if (user.isAdmin && user.scope.indexOf(tenant.name) !== -1) {
|
||||||
|
@ -311,4 +321,4 @@ export default connect(state => ({
|
||||||
tenant: state.tenant,
|
tenant: state.tenant,
|
||||||
user: state.user,
|
user: state.user,
|
||||||
preferences: state.preferences,
|
preferences: state.preferences,
|
||||||
}))(Change)
|
}))(Item)
|
|
@ -1,4 +1,5 @@
|
||||||
// Copyright 2018 Red Hat, Inc
|
// Copyright 2018 Red Hat, Inc
|
||||||
|
// Copyright 2024 Acme Gating, LLC
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may
|
// Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
// not use this file except in compliance with the License. You may obtain
|
// not use this file except in compliance with the License. You may obtain
|
||||||
|
@ -20,11 +21,15 @@ import * as moment from 'moment'
|
||||||
import 'moment-duration-format'
|
import 'moment-duration-format'
|
||||||
import { Button } from '@patternfly/react-core'
|
import { Button } from '@patternfly/react-core'
|
||||||
|
|
||||||
|
function getChanges(item) {
|
||||||
|
// For backwards compat: get a list of this items changes.
|
||||||
|
return 'changes' in item ? item.changes : [item]
|
||||||
|
}
|
||||||
|
|
||||||
class ChangePanel extends React.Component {
|
class ItemPanel extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
globalExpanded: PropTypes.bool.isRequired,
|
globalExpanded: PropTypes.bool.isRequired,
|
||||||
change: PropTypes.object.isRequired,
|
item: PropTypes.object.isRequired,
|
||||||
tenant: PropTypes.object,
|
tenant: PropTypes.object,
|
||||||
preferences: PropTypes.object
|
preferences: PropTypes.object
|
||||||
}
|
}
|
||||||
|
@ -175,13 +180,13 @@ class ChangePanel extends React.Component {
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<small title='Remaining Time' className='time' style={{display: 'inline'}}>
|
|
||||||
{remainingTime}
|
|
||||||
</small>
|
|
||||||
<br />
|
|
||||||
<small title='Elapsed Time' className='time' style={{display: 'inline'}}>
|
<small title='Elapsed Time' className='time' style={{display: 'inline'}}>
|
||||||
{this.enqueueTime(change.enqueue_time)}
|
{this.enqueueTime(change.enqueue_time)}
|
||||||
</small>
|
</small>
|
||||||
|
<small> | </small>
|
||||||
|
<small title='Remaining Time' className='time' style={{display: 'inline'}}>
|
||||||
|
{remainingTime}
|
||||||
|
</small>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -347,12 +352,12 @@ class ChangePanel extends React.Component {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
calculateTimes (change) {
|
calculateTimes (item) {
|
||||||
let maxRemaining = 0
|
let maxRemaining = 0
|
||||||
let jobs = {}
|
let jobs = {}
|
||||||
const now = Date.now()
|
const now = Date.now()
|
||||||
|
|
||||||
for (const job of change.jobs) {
|
for (const job of item.jobs) {
|
||||||
let jobElapsed = null
|
let jobElapsed = null
|
||||||
let jobRemaining = null
|
let jobRemaining = null
|
||||||
if (job.start_time) {
|
if (job.start_time) {
|
||||||
|
@ -378,7 +383,7 @@ class ChangePanel extends React.Component {
|
||||||
}
|
}
|
||||||
// If not all the jobs have started, this will be null, so only
|
// If not all the jobs have started, this will be null, so only
|
||||||
// use our value if it's oky to calculate it.
|
// use our value if it's oky to calculate it.
|
||||||
if (change.remaininging_time === null) {
|
if (item.remaininging_time === null) {
|
||||||
maxRemaining = null
|
maxRemaining = null
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
@ -389,36 +394,40 @@ class ChangePanel extends React.Component {
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { expanded } = this.state
|
const { expanded } = this.state
|
||||||
const { change, globalExpanded } = this.props
|
const { item, globalExpanded } = this.props
|
||||||
let expand = globalExpanded
|
let expand = globalExpanded
|
||||||
if (this.clicked) {
|
if (this.clicked) {
|
||||||
expand = expanded
|
expand = expanded
|
||||||
}
|
}
|
||||||
const times = this.calculateTimes(change)
|
const times = this.calculateTimes(item)
|
||||||
const header = (
|
const header = (
|
||||||
<div className={`panel panel-default ${this.props.preferences.darkMode ? 'zuul-change-dark' : 'zuul-change'}`}>
|
<div className={`panel panel-default ${this.props.preferences.darkMode ? 'zuul-change-dark' : 'zuul-change'}`}>
|
||||||
<div className={`panel-heading ${this.props.preferences.darkMode ? 'zuul-patchset-header-dark' : 'zuul-patchset-header'}`}
|
<div className={`panel-heading ${this.props.preferences.darkMode ? 'zuul-patchset-header-dark' : 'zuul-patchset-header'}`}
|
||||||
onClick={this.onClick}>
|
onClick={this.onClick}>
|
||||||
<div className='row'>
|
<div>
|
||||||
<div className='col-xs-8'>
|
{item.live === true ? (
|
||||||
<span className='change_project'>{change.project}</span>
|
|
||||||
<div className='row'>
|
<div className='row'>
|
||||||
<div className='col-xs-4'>
|
<div className='col-xs-6'>
|
||||||
{this.renderChangeLink(change)}
|
{this.renderProgressBar(item)}
|
||||||
</div>
|
</div>
|
||||||
<div className='col-xs-8'>
|
<div className='col-xs-6 text-right'>
|
||||||
{this.renderProgressBar(change)}
|
{this.renderTimer(item, times)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
{change.live === true ? (
|
|
||||||
<div className='col-xs-4 text-right'>
|
|
||||||
{this.renderTimer(change, times)}
|
|
||||||
</div>
|
|
||||||
) : ''}
|
) : ''}
|
||||||
|
{getChanges(item).map((change, idx) => (
|
||||||
|
<div key={idx} className='row'>
|
||||||
|
<div className='col-xs-8'>
|
||||||
|
<span className='change_project'>{change.project}</span>
|
||||||
|
</div>
|
||||||
|
<div className='col-xs-4 text-right'>
|
||||||
|
{this.renderChangeLink(change)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{expand ? this.renderJobList(change.jobs, times) : ''}
|
{expand ? this.renderJobList(item.jobs, times) : ''}
|
||||||
</div >
|
</div >
|
||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
|
@ -432,4 +441,4 @@ class ChangePanel extends React.Component {
|
||||||
export default connect(state => ({
|
export default connect(state => ({
|
||||||
tenant: state.tenant,
|
tenant: state.tenant,
|
||||||
preferences: state.preferences,
|
preferences: state.preferences,
|
||||||
}))(ChangePanel)
|
}))(ItemPanel)
|
|
@ -1,4 +1,5 @@
|
||||||
// Copyright 2018 Red Hat, Inc
|
// Copyright 2018 Red Hat, Inc
|
||||||
|
// Copyright 2024 Acme Gating, LLC
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may
|
// Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
// not use this file except in compliance with the License. You may obtain
|
// not use this file except in compliance with the License. You may obtain
|
||||||
|
@ -20,11 +21,13 @@ import { Button } from '@patternfly/react-core'
|
||||||
|
|
||||||
import { setTenantAction } from '../../actions/tenant'
|
import { setTenantAction } from '../../actions/tenant'
|
||||||
import configureStore from '../../store'
|
import configureStore from '../../store'
|
||||||
import ChangePanel from './ChangePanel'
|
import ItemPanel from './ItemPanel'
|
||||||
|
|
||||||
|
|
||||||
const fakeChange = {
|
const fakeItem = {
|
||||||
project: 'org-project',
|
changes: [{
|
||||||
|
project: 'org-project'
|
||||||
|
}],
|
||||||
jobs: [{
|
jobs: [{
|
||||||
name: 'job-name',
|
name: 'job-name',
|
||||||
url: 'stream/42',
|
url: 'stream/42',
|
||||||
|
@ -32,14 +35,13 @@ const fakeChange = {
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
it('item panel render multi tenant links', () => {
|
||||||
it('change panel render multi tenant links', () => {
|
|
||||||
const store = configureStore()
|
const store = configureStore()
|
||||||
store.dispatch(setTenantAction('tenant-one', false))
|
store.dispatch(setTenantAction('tenant-one', false))
|
||||||
const application = create(
|
const application = create(
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<Router>
|
<Router>
|
||||||
<ChangePanel change={fakeChange} globalExpanded={true} />
|
<ItemPanel item={fakeItem} globalExpanded={true} />
|
||||||
</Router>
|
</Router>
|
||||||
</Provider>
|
</Provider>
|
||||||
)
|
)
|
||||||
|
@ -50,13 +52,13 @@ it('change panel render multi tenant links', () => {
|
||||||
expect(skipButton === undefined)
|
expect(skipButton === undefined)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('change panel render white-label tenant links', () => {
|
it('item panel render white-label tenant links', () => {
|
||||||
const store = configureStore()
|
const store = configureStore()
|
||||||
store.dispatch(setTenantAction('tenant-one', true))
|
store.dispatch(setTenantAction('tenant-one', true))
|
||||||
const application = create(
|
const application = create(
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<Router>
|
<Router>
|
||||||
<ChangePanel change={fakeChange} globalExpanded={true} />
|
<ItemPanel item={fakeItem} globalExpanded={true} />
|
||||||
</Router>
|
</Router>
|
||||||
</Provider>
|
</Provider>
|
||||||
)
|
)
|
||||||
|
@ -67,7 +69,77 @@ it('change panel render white-label tenant links', () => {
|
||||||
expect(skipButton === undefined)
|
expect(skipButton === undefined)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('change panel skip jobs', () => {
|
it('item panel skip jobs', () => {
|
||||||
|
const fakeItem = {
|
||||||
|
changes: [{
|
||||||
|
project: 'org-project'
|
||||||
|
}],
|
||||||
|
jobs: [{
|
||||||
|
name: 'job-name',
|
||||||
|
url: 'stream/42',
|
||||||
|
result: 'skipped'
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
const store = configureStore()
|
||||||
|
store.dispatch(setTenantAction('tenant-one', true))
|
||||||
|
const application = create(
|
||||||
|
<Provider store={store}>
|
||||||
|
<Router>
|
||||||
|
<ItemPanel item={fakeItem} globalExpanded={true} />
|
||||||
|
</Router>
|
||||||
|
</Provider>
|
||||||
|
)
|
||||||
|
const skipButton = application.root.findByType(Button)
|
||||||
|
expect(skipButton.props.children.includes('skipped job'))
|
||||||
|
})
|
||||||
|
|
||||||
|
/* Backwards compat; remove after circular dependency refactor */
|
||||||
|
|
||||||
|
const fakeChange = {
|
||||||
|
project: 'org-project',
|
||||||
|
jobs: [{
|
||||||
|
name: 'job-name',
|
||||||
|
url: 'stream/42',
|
||||||
|
result: null
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
it('item panel backwards compat render multi tenant links', () => {
|
||||||
|
const store = configureStore()
|
||||||
|
store.dispatch(setTenantAction('tenant-one', false))
|
||||||
|
const application = create(
|
||||||
|
<Provider store={store}>
|
||||||
|
<Router>
|
||||||
|
<ItemPanel item={fakeChange} globalExpanded={true} />
|
||||||
|
</Router>
|
||||||
|
</Provider>
|
||||||
|
)
|
||||||
|
const jobLink = application.root.findByType(Link)
|
||||||
|
expect(jobLink.props.to).toEqual(
|
||||||
|
'/t/tenant-one/stream/42')
|
||||||
|
const skipButton = application.root.findAllByType(Button)
|
||||||
|
expect(skipButton === undefined)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('item panel backwards compat render white-label tenant links', () => {
|
||||||
|
const store = configureStore()
|
||||||
|
store.dispatch(setTenantAction('tenant-one', true))
|
||||||
|
const application = create(
|
||||||
|
<Provider store={store}>
|
||||||
|
<Router>
|
||||||
|
<ItemPanel item={fakeChange} globalExpanded={true} />
|
||||||
|
</Router>
|
||||||
|
</Provider>
|
||||||
|
)
|
||||||
|
const jobLink = application.root.findByType(Link)
|
||||||
|
expect(jobLink.props.to).toEqual(
|
||||||
|
'/stream/42')
|
||||||
|
const skipButton = application.root.findAllByType(Button)
|
||||||
|
expect(skipButton === undefined)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('item panel backwards compat skip jobs', () => {
|
||||||
const fakeChange = {
|
const fakeChange = {
|
||||||
project: 'org-project',
|
project: 'org-project',
|
||||||
jobs: [{
|
jobs: [{
|
||||||
|
@ -82,7 +154,7 @@ it('change panel skip jobs', () => {
|
||||||
const application = create(
|
const application = create(
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<Router>
|
<Router>
|
||||||
<ChangePanel change={fakeChange} globalExpanded={true} />
|
<ItemPanel item={fakeChange} globalExpanded={true} />
|
||||||
</Router>
|
</Router>
|
||||||
</Provider>
|
</Provider>
|
||||||
)
|
)
|
|
@ -209,7 +209,7 @@ a.refresh {
|
||||||
|
|
||||||
.zuul-change-total-result {
|
.zuul-change-total-result {
|
||||||
height: 10px;
|
height: 10px;
|
||||||
width: 100px;
|
width: 180px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
|
|
@ -18,7 +18,7 @@ import { connect } from 'react-redux'
|
||||||
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
|
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
|
||||||
|
|
||||||
import { fetchChangeIfNeeded } from '../actions/change'
|
import { fetchChangeIfNeeded } from '../actions/change'
|
||||||
import ChangePanel from '../containers/status/ChangePanel'
|
import ItemPanel from '../containers/status/ItemPanel'
|
||||||
import { Fetchable } from '../containers/Fetching'
|
import { Fetchable } from '../containers/Fetching'
|
||||||
|
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ class ChangeStatusPage extends React.Component {
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { remoteData } = this.props
|
const { remoteData } = this.props
|
||||||
const change = remoteData.change
|
const itemlist = remoteData.change
|
||||||
return (
|
return (
|
||||||
<PageSection variant={PageSectionVariants.light}>
|
<PageSection variant={PageSectionVariants.light}>
|
||||||
<PageSection style={{paddingRight: '5px'}}>
|
<PageSection style={{paddingRight: '5px'}}>
|
||||||
|
@ -72,11 +72,11 @@ class ChangeStatusPage extends React.Component {
|
||||||
fetchCallback={this.updateData}
|
fetchCallback={this.updateData}
|
||||||
/>
|
/>
|
||||||
</PageSection>
|
</PageSection>
|
||||||
{change && change.map((item, idx) => (
|
{itemlist && itemlist.map((item, idx) => (
|
||||||
<div className='row zuul-change-content' key={idx}>
|
<div className='row zuul-change-content' key={idx}>
|
||||||
<ChangePanel
|
<ItemPanel
|
||||||
globalExpanded={true}
|
globalExpanded={true}
|
||||||
change={item}
|
item={item}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|
Loading…
Reference in New Issue