Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(js): add Download and QR Popup buttons to collapsed build blocks #404

Merged
merged 1 commit into from
Oct 13, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions web/src/assets/svg/yolo-logo-square.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 3 additions & 2 deletions web/src/ui/components/Build/ArtifactRow.js
Original file line number Diff line number Diff line change
@@ -28,14 +28,15 @@ const ArtifactRowKindIcon = ({ color, kind = '' }) => (
/>
)

const QrCode = ({ artifactPlistSignedUrl, closeAction }) => (
export const QrCode = ({ artifactPlistSignedUrl, closeAction }) => (
<QRCodeModal closeAction={closeAction}>
<QRCode
value={`itms-services://?action=download-manifest&url=${process.env.API_SERVER}${artifactPlistSignedUrl}`}
size={256}
// size={256}
level="M"
renderAs="svg"
includeMargin
style={{ width: '100%' }}
/>
</QRCodeModal>
)
3 changes: 1 addition & 2 deletions web/src/ui/components/Build/BuildBlockHeader.js
Original file line number Diff line number Diff line change
@@ -74,8 +74,7 @@ const ChevronIcon = ({ theme, collapsed, toggleCollapsed }) => (
<div
className={styles.headerChevronToggler}
style={{ color: theme.text.blockTitle }}
onClick={(e) => {
e.stopPropagation()
onClick={() => {
toggleCollapsed(!collapsed)
}}
>
246 changes: 179 additions & 67 deletions web/src/ui/components/Build/BuildContainer.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { faQrcode } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { get } from 'lodash'
import React, { useContext, useState } from 'react'
import { Download } from 'react-feather'
import { ARTIFACT_KIND_NAMES, BRANCH, BUILD_STATE } from '../../../constants'
import { GlobalContext } from '../../../store/GlobalStore'
import { ThemeContext } from '../../../store/ThemeStore'
@@ -10,9 +12,13 @@ import {
getStrEquNormalized,
} from '../../../util/getters'
import { getArtifactKindIcon } from '../../styleTools/brandIcons'
import { tagColorStyles } from '../../styleTools/buttonStyler'
import {
primaryButtonColors,
tagColorStyles,
} from '../../styleTools/buttonStyler'
import ShowingOlderBuildsTag from '../ShowingOlderBuildsTag'
import Tag from '../Tag/Tag'
import { QrCode } from './ArtifactRow'
import styles from './Build.module.scss'
import BuildAndMrContainer from './BuildAndMrContainer'
import BuildBlockHeader from './BuildBlockHeader'
@@ -63,13 +69,114 @@ const AnyRunningBuildTags = ({ hasRunningBuilds, allBuildsForMr, theme }) => has
</Tag>
)

const LatestBuildQrButton = ({ onClick, theme, artifactPlistSignedUrl }) => artifactPlistSignedUrl && (
<div
onClick={(e) => {
onClick()
e.stopPropagation()
}}
className="btn btn-sm"
style={{
...primaryButtonColors(theme),
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
title="Show QR code"
>
<FontAwesomeIcon
icon={faQrcode}
size="lg"
color={theme.text.btnPrimary}
style={{
marginTop: 0,
marginBottom: 0,
}}
/>
</div>
)

const DlButtonSmall = ({ buildHasArtifacts, theme }) => buildHasArtifacts && (
<>
{buildHasArtifacts.map((artifact, i) => {
const {
plist_signed_url: artifactPlistSignedUrl = '',
dl_artifact_signed_url: artifactDlArtifactSignedUrl = '',
kind: artifactKind = '',
} = artifact

const fullPlistSignedUrl = artifactPlistSignedUrl
&& `itms-services://?action=download-manifest&url=${process.env.API_SERVER}${artifactPlistSignedUrl}`

const fullDlArtifactSignedUrl = artifactDlArtifactSignedUrl
&& `${process.env.API_SERVER}${artifactDlArtifactSignedUrl}`

const hasDlUrl = fullPlistSignedUrl || fullDlArtifactSignedUrl
return (
<a
key={`${artifactPlistSignedUrl}=${i}`}
href={hasDlUrl}
className="btn btn-sm"
style={{
...primaryButtonColors(theme),
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
title={hasDlUrl}
>
<Download size="1rem" style={{ marginRight: '0.3rem' }} />
{`.${ARTIFACT_KIND_NAMES[artifactKind]}`}
</a>
)
})}
</>
)

const LatestBuildStateTags = ({
collapsed,
theme,
buildState,
buildId,
buildHasArtifacts,
allBuildsForMr,
hasRunningBuilds,
}) => {
const [showingQrModal, toggleShowQrModal] = useState(false)
const firstArtifactPlistSignedUrl = buildHasArtifacts?.find((a) => a.kind === ARTIFACT_KIND_NAMES.IPA)
?.plist_signed_url || null
return (
collapsed && (
<>
{showingQrModal && firstArtifactPlistSignedUrl && (
<QrCode
artifactPlistSignedUrl={firstArtifactPlistSignedUrl}
closeAction={() => toggleShowQrModal(false)}
/>
)}
<BuildStateTag {...{ theme, buildState, buildId }} />
<LatestBuildArtifactsIcons {...{ theme, buildHasArtifacts }} />
<AnyRunningBuildTags {...{ hasRunningBuilds, allBuildsForMr, theme }} />
<DlButtonSmall {...{ buildHasArtifacts, theme }} />
<LatestBuildQrButton
onClick={() => toggleShowQrModal(true)}
theme={theme}
artifactPlistSignedUrl={firstArtifactPlistSignedUrl}
/>
<ShowingOlderBuildsTag nOlderBuilds={allBuildsForMr.length - 1} />
</>
)
)
}

const BuildContainer = React.memo(
({
build, toCollapse, hasRunningBuilds, isLatestMaster = false,
}) => {
const { state } = useContext(GlobalContext)
const [collapsed, setCollapsed] = useState(toCollapse)
const [showingAllBuilds, toggleShowingAllBuilds] = useState(false)

const { theme } = useContext(ThemeContext)

const toggleCollapsed = () => setCollapsed(!collapsed)
@@ -105,75 +212,80 @@ const BuildContainer = React.memo(

const isMasterBuildBranch = getStrEquNormalized(buildBranch, BRANCH.MASTER)

const LatestBuildStateTags = () => collapsed && (
<>
<BuildStateTag {...{ theme, buildState, buildId }} />
<LatestBuildArtifactsIcons {...{ theme, buildHasArtifacts }} />
<ShowingOlderBuildsTag nOlderBuilds={allBuildsForMr.length - 1} />
<AnyRunningBuildTags
{...{ hasRunningBuilds, allBuildsForMr, theme }}
/>
</>
)

return (
<div className={styles.buildBlock}>
<div
className="card"
style={{
backgroundColor: theme.bg.block,
boxShadow: theme.shadowStyle.block,
...tablerOverrides.card,
}}
key={buildId}
onClick={() => {
if (collapsed) {
toggleCollapsed()
}
}}
>
<BuildBlockHeader
{...{
buildAuthorName,
buildAuthorAvatarUrl,
buildAuthorId,
buildHasMr,
buildId,
buildShortId,
collapsed,
isMasterBuildBranch,
isLatestMaster,
mrId,
mrTitle,
mrShortId,
mrState,
toggleCollapsed,
projectOwnerId,
projectOwnerAvatarUrl,
...{ childrenLatestBuildTags: <LatestBuildStateTags /> },
<>
<div className={styles.buildBlock}>
<div
className="card"
style={{
backgroundColor: theme.bg.block,
boxShadow: theme.shadowStyle.block,
...tablerOverrides.card,
}}
/>
{!collapsed
&& allBuildsForMr
.filter((bIdx, i) => showingAllBuilds ? Number.isInteger(bIdx) : i === 0)
.map((buildidx, i) => (
<BuildAndMrContainer
build={state.builds[buildidx]}
buildHasMr={buildHasMr}
hasRunningBuilds={hasRunningBuilds}
isLatestBuild={i === 0}
key={i}
nOlderBuilds={
i === 0 && getIsArrayWithN(allBuildsForMr, 2)
? allBuildsForMr.length - 1
: 0
}
showingAllBuilds={showingAllBuilds}
toggleShowingAllBuilds={toggleShowingAllBuilds}
/>
))}
key={buildId}
onClick={() => {
if (collapsed) {
toggleCollapsed()
}
}}
>
<BuildBlockHeader
{...{
buildAuthorName,
buildAuthorAvatarUrl,
buildAuthorId,
buildHasMr,
buildId,
buildShortId,
collapsed,
isMasterBuildBranch,
isLatestMaster,
mrId,
mrTitle,
mrShortId,
mrState,
toggleCollapsed,
projectOwnerId,
projectOwnerAvatarUrl,
...{
childrenLatestBuildTags: (
<LatestBuildStateTags
{...{
collapsed,
theme,
buildState,
buildId,
buildHasArtifacts,
allBuildsForMr,
hasRunningBuilds,
}}
/>
),
},
}}
/>
{!collapsed
&& allBuildsForMr
.filter((bIdx, i) => showingAllBuilds ? Number.isInteger(bIdx) : i === 0)
.map((buildidx, i) => (
<BuildAndMrContainer
build={state.builds[buildidx]}
buildHasMr={buildHasMr}
hasRunningBuilds={hasRunningBuilds}
isLatestBuild={i === 0}
key={i}
nOlderBuilds={
i === 0 && getIsArrayWithN(allBuildsForMr, 2)
? allBuildsForMr.length - 1
: 0
}
showingAllBuilds={showingAllBuilds}
toggleShowingAllBuilds={toggleShowingAllBuilds}
/>
))}
</div>
</div>
</div>
</>
)
},
)
9 changes: 7 additions & 2 deletions web/src/ui/components/BuildList.js
Original file line number Diff line number Diff line change
@@ -162,13 +162,18 @@ const BuildList = ({ builds = [], loaded }) => {

useEffect(() => {
// On show feed, scroll to feed with 'hide feed' button at top of screen
if (refOpen?.current && displayFeed === true && prevDisplay === false) {
if (
refOpen?.current
&& displayFeed === true
&& prevDisplay === false
&& builds.length
) {
refOpen.current.scrollIntoView({
behavior: 'smooth',
block: 'start',
})
}
}, [displayFeed, refOpen, prevDisplay])
}, [displayFeed, refOpen, prevDisplay, builds.length])

return !builds.length > 0 && loaded ? (
<NoBuilds />
29 changes: 22 additions & 7 deletions web/src/ui/components/MessageModal/MessageModal.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,30 @@
import React from 'react'
import './MessageModal.scss'

const MessageModal = ({ children }) => (
const MessageModal = ({ children, onClose = () => {} }) => (
<>
<div className="faded" />
<div
className="faded"
onClick={(e) => {
e.stopPropagation()
onClose()
}}
/>
<div className="MessageModal">
<div className="modal modal-blur fade show">
<div className="modal-dialog" role="document">
<div className="modal-content">
{children}
</div>
<div
className="modal modal-blur fade show"
onClick={(e) => {
e.stopPropagation()
onClose()
}}
>
<div
className="modal-dialog"
onClick={(e) => {
e.stopPropagation()
}}
>
<div className="modal-content">{children}</div>
</div>
</div>
</div>
77 changes: 39 additions & 38 deletions web/src/ui/components/MessageModal/MessageModal.scss
Original file line number Diff line number Diff line change
@@ -1,47 +1,48 @@
@import '../../../assets/variables';
@import "../../../assets/variables";

.MessageModal {
.modal.modal-blur.fade.show {
padding-right: 15px;
display: block;
top: 33%;
left: 0;
right: 0;
}
.modal.modal-blur.fade.show {
padding-right: 15px;
display: block;
top: 33vmin;
left: 0;
right: 0;
}

.modal-dialog .modal-content {
border-radius: 15px;
border: none;
padding: 15px;
color: $body-bg-dark;
background-color: #f7d68e;
text-align: center;
}
.modal-dialog .modal-content {
border-radius: 15px;
border: none;
padding: 15px;
padding-top: 25px;
color: $body-bg-dark;
background-color: #f7d68e;
text-align: center;
}

.modal-content .modal-header {
border-bottom: none;
}
.modal-content .modal-header {
border-bottom: none;
}

.modal-content .modal-footer {
border-top: none;
justify-content: center;
flex-basis: 100%;
}
.modal-content .modal-footer {
border-top: none;
justify-content: center;
flex-basis: 100%;
}

.modal-title {
font-size: larger;
flex-basis: 100%;
}
.modal-title {
font-size: larger;
flex-basis: 100%;
}

button.btn.btn-sm.btn-shadow {
background-color: transparent;
border-width: 1px;
border-radius: 15%;
border-color: darken(#f7d68e, 20%);
box-shadow: 0px 0.25rem 0px darken(#f7d68e, 30%);
border-style: solid;
&:hover {
background-color: darken(#f7d68e, 10%);
button.btn.btn-sm.btn-shadow {
background-color: transparent;
border-width: 1px;
border-radius: 15%;
border-color: darken(#f7d68e, 20%);
box-shadow: 0px 0.25rem 0px darken(#f7d68e, 30%);
border-style: solid;
&:hover {
background-color: darken(#f7d68e, 10%);
}
}
}
}
9 changes: 8 additions & 1 deletion web/src/ui/components/QRCodeModal.js
Original file line number Diff line number Diff line change
@@ -2,7 +2,14 @@ import React from 'react'
import MessageModal from './MessageModal/MessageModal'

const QRCodeModal = ({ closeAction, children }) => (
<MessageModal>
<MessageModal onClose={closeAction}>
<h2 style={{ color: 'darkgoldenrod', fontSize: '1.4rem' }}>
Scan me!
{' '}
<span role="img" aria-label="a cellular phone">
📱
</span>
</h2>
<div style={{ width: 'auto' }}>
{children}
<div className="modal-footer">
5 changes: 3 additions & 2 deletions web/src/ui/pages/Home/Home.module.scss
Original file line number Diff line number Diff line change
@@ -18,7 +18,8 @@
}

.footer {
flex: 0 1 auto;
// flex: 0 1 auto;
width: 100%;
padding: 1.25rem;
height: 0;
// padding: 1.25rem;
}