Improve wrapped text rendering on application list and application sync status pages (#2067)

This commit is contained in:
Alexander Matyushentsev 2019-07-31 18:39:41 -07:00 committed by GitHub
parent 29b72ca695
commit dacdeb6025
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 114 additions and 58 deletions

View file

@ -8,4 +8,12 @@
left: 15px;
position: relative;
}
}
&__message {
white-space: normal;
line-height: 16px;
display: inline-block;
vertical-align: middle;
}
}

View file

@ -91,12 +91,9 @@ export const ApplicationOperationState: React.StatelessComponent<Props> = ({appl
<div className='argo-table-list__head'>
<div className='row'>
<div className='columns large-1 show-for-large application-operation-state__icons_container_padding'>
API VERSION
</div>
<div className='columns large-1 show-for-large'>
KIND
</div>
<div className='columns large-1 show-for-large'>
<div className='columns large-2 show-for-large'>
NAMESPACE
</div>
<div className='columns large-2 small-2'>
@ -120,12 +117,9 @@ export const ApplicationOperationState: React.StatelessComponent<Props> = ({appl
<div className='application-operation-state__icons_container'>
{resource.hookType && (<i title='Resource lifecycle hook' className='fa fa-anchor' />)}
</div>
{resource.group ? resource.group + '/' + resource.version : resource.version}
{resource.group ? resource.group + '/' + resource.version : resource.version}/{resource.kind}
</div>
<div className='columns large-1 show-for-large'>
{resource.kind}
</div>
<div className='columns large-1 show-for-large'>
<div className='columns large-2 show-for-large'>
{resource.namespace}
</div>
<div className='columns large-2 small-2'>
@ -138,8 +132,10 @@ export const ApplicationOperationState: React.StatelessComponent<Props> = ({appl
<div className='columns large-1 show-for-large'>
{resource.hookType}
</div>
<div className='columns large-4 small-8 wrap'>
{resource.message}
<div className='columns large-4 small-8'>
<div className='application-operation-state__message'>
{resource.message}
</div>
</div>
</div>
</div>

View file

@ -5,12 +5,11 @@ import { FormApi, Text } from 'react-form';
require('./application-summary.scss');
import { Cluster, clusterTitle, DataLoader, EditablePanel, EditablePanelItem } from '../../../shared/components';
import { Repo, Revision } from '../../../shared/components';
import { Consumer } from '../../../shared/context';
import * as models from '../../../shared/models';
import { services } from '../../../shared/services';
import {Repo} from '../../../shared/components/repo';
import {Revision} from '../../../shared/components/revision';
import { ComparisonStatusIcon, HealthStatusIcon, syncStatusMessage } from '../utils';
const urlPattern = new RegExp('^(https?:\\/\\/)?((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|((\\d{1,3}\\.){3}\\d{1,3}))'

View file

@ -190,12 +190,6 @@
& > .columns:first-child {
padding-left: 30px;
}
& > .columns:last-child {
.argo-dropdown {
position: absolute;
right: 0;
}
}
margin-left: -30px !important;
}

View file

@ -5,7 +5,7 @@ import * as React from 'react';
import { RouteComponentProps } from 'react-router';
import { Observable } from 'rxjs';
import { Autocomplete, DataLoader, EmptyState, ObservableQuery, Page, Paginate, Query } from '../../../shared/components';
import { Autocomplete, ClusterCtx, DataLoader, EmptyState, ObservableQuery, Page, Paginate, Query } from '../../../shared/components';
import { Consumer } from '../../../shared/context';
import * as models from '../../../shared/models';
import { AppsListPreferences, AppsListViewType, services } from '../../../shared/services';
@ -112,6 +112,7 @@ export const ApplicationsList = (props: RouteComponentProps<{}>) => {
const [createApi, setCreateApi] = React.useState(null);
return (
<ClusterCtx.Provider value={services.clusters.list()}>
<Consumer>{
(ctx) => (
<Page title='Applications' toolbar={services.viewPreferences.getPreferences().map((pref) => ({
@ -277,5 +278,6 @@ export const ApplicationsList = (props: RouteComponentProps<{}>) => {
</SlidingPanel>
</Page>
)}
</Consumer>);
</Consumer>
</ClusterCtx.Provider>);
};

View file

@ -0,0 +1,26 @@
@import 'node_modules/argo-ui/src/app/shared/styles/config';
.applications-table {
&__revision {
background-color: $argo-color-gray-4;
border-radius: 5px;
position: absolute;
right: 5px;
padding: 0 2px;
}
.argo-table-list__row {
line-height: 26px;
padding-top: 4px;
padding-bottom: 4px;
.columns:last-child {
.argo-dropdown {
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
}
}
}
}

View file

@ -1,11 +1,19 @@
import { DropDownMenu } from 'argo-ui';
import { DropDownMenu, Tooltip } from 'argo-ui';
import * as React from 'react';
import { Cluster } from '../../../shared/components';
import { Consumer } from '../../../shared/context';
import * as models from '../../../shared/models';
import { ApplicationURLs } from '../application-urls';
import * as AppUtils from '../utils';
require('./applications-table.scss');
function shortRepo(repo: string) {
const url = new URL(repo);
return <Tooltip content={repo}><span>{url.pathname.slice(1)}</span></Tooltip>;
}
export const ApplicationsTable = (props: {
applications: models.Application[];
syncApplication: (appName: string) => any;
@ -14,37 +22,39 @@ export const ApplicationsTable = (props: {
}) => (
<Consumer>
{(ctx) => (
<div className='argo-table-list argo-table-list--clickable'>
<div className='argo-table-list__head'>
<div className='row'>
<div className='columns large-3 small-6'>PROJECT/NAME</div>
<div className='columns large-3 show-for-large'>SOURCE</div>
<div className='columns large-1 small-2'>TARGET REVISION</div>
<div className='columns large-3 show-for-large'>DESTINATION</div>
<div className='columns large-2 small-4'>STATUS</div>
</div>
</div>
<div className='applications-table argo-table-list argo-table-list--clickable'>
{props.applications.map((app) => (
<div key={app.metadata.name} className={`argo-table-list__row
applications-list__entry applications-list__entry--comparison-${app.status.sync.status}
applications-list__entry--health-${app.status.health.status}`
}>
<div className='row applications-list__table-row' onClick={(e) => ctx.navigation.goto(`/applications/${app.metadata.name}`, {}, { event: e })}>
<div className='columns large-3 small-6 wrap'>
<i className='icon argo-icon-application'/> {app.spec.project}/{app.metadata.name} <ApplicationURLs urls={app.status.summary.externalURLs}/>
<div className='columns small-4'>
<div className='row'>
<div className='show-for-xxlarge columns small-3'>Project:</div>
<div className='columns small-12 xxlarge-9'>{app.spec.project}</div>
</div>
<div className='row'>
<div className='show-for-xxlarge columns small-3'>Name:</div>
<div className='columns small-12 xxlarge-9'>{app.metadata.name} <ApplicationURLs urls={app.status.summary.externalURLs}/></div>
</div>
</div>
<div className='columns large-3 show-for-large wrap'>
{app.spec.source.repoURL}/{app.spec.source.path}
<div className='columns small-6'>
<div className='row'>
<div className='show-for-xxlarge columns small-2'>Source:</div>
<div className='columns small-12 xxlarge-10' style={{position: 'relative'}}>
{shortRepo(app.spec.source.repoURL)}/{app.spec.source.path}
<span className='applications-table__revision'>{app.spec.source.targetRevision || 'HEAD'}</span>
</div>
</div>
<div className='row'>
<div className='show-for-xxlarge columns small-2'>Destination:</div>
<div className='columns small-12 xxlarge-10'><Cluster url={app.spec.destination.server}/>/{app.spec.destination.namespace}</div>
</div>
</div>
<div className='columns large-1 small-2'>
{app.spec.source.targetRevision || 'HEAD'}
</div>
<div className='columns large-3 show-for-large wrap'>
{app.spec.destination.server}/{app.spec.destination.namespace}
</div>
<div className='columns large-2 small-4'>
<div className='columns small-2'>
<AppUtils.HealthStatusIcon state={app.status.health}/> <span>{app.status.health.status}</span>
&nbsp;
<br/>
<AppUtils.ComparisonStatusIcon status={app.status.sync.status}/> <span>{app.status.sync.status}</span>
<DropDownMenu anchor={() => (
<button className='argo-button argo-button--light argo-button--lg argo-button--short'>

View file

@ -67,7 +67,7 @@ export const ApplicationTiles = ({applications, syncApplication, refreshApplicat
</div>
<div className='row'>
<div className='columns small-3'>Namespace:</div>
<div className='columns small-9 wrap'>
<div className='columns small-9'>
{app.spec.destination.namespace}
</div>
</div>

View file

@ -4,8 +4,7 @@ import * as React from 'react';
import {Form, FormApi, Text, TextArea} from 'react-form';
import {RouteComponentProps} from 'react-router';
import {CheckboxField, ConnectionStateIcon, DataLoader, EmptyState, ErrorNotification, Page} from '../../../shared/components';
import {Repo} from '../../../shared/components/repo';
import {CheckboxField, ConnectionStateIcon, DataLoader, EmptyState, ErrorNotification, Page, Repo} from '../../../shared/components';
import {AppContext} from '../../../shared/context';
import * as models from '../../../shared/models';
import {services} from '../../../shared/services';

View file

@ -17,14 +17,34 @@ const clusterHTML = (cluster: models.Cluster, showUrl: boolean) => {
return <Tooltip content={cluster.server}><span>{text}</span></Tooltip>;
};
interface Props {
url: string;
showUrl?: boolean;
async function getCluster(clusters: Promise<models.Cluster[]>, url: string): Promise<models.Cluster> {
let cluster: models.Cluster;
if (clusters) {
cluster = await clusters.then((items) => items.find((item) => item.server === url));
} else {
try {
cluster = await services.clusters.get(url);
} catch {
cluster = null;
}
}
if (!cluster) {
cluster = {
connectionState: null,
name: url,
server: url,
};
}
return cluster;
}
export const Cluster = React.memo((props: Props) => {
return (
<DataLoader input={props.url}
load={(url) => services.clusters.get(url)}>{(cluster: models.Cluster) => clusterHTML(cluster, props.showUrl)}</DataLoader>
);
});
export const ClusterCtx = React.createContext<Promise<Array<models.Cluster>>>(null);
export const Cluster = (props: {url: string; showUrl?: boolean; }) => (
<ClusterCtx.Consumer>
{(clusters) => (
<DataLoader input={props.url} loadingRenderer={() => <span>{props.url}</span>}
load={(url) => getCluster(clusters, url)}>{(cluster: models.Cluster) => clusterHTML(cluster, props.showUrl)}</DataLoader>
)}
</ClusterCtx.Consumer>
);

View file

@ -16,3 +16,5 @@ export * from './autocomplete/autocomplete';
export * from './autocomplete/autocomplete-field';
export * from './monaco-editor';
export * from './yaml-editor/yaml-editor';
export * from './repo';
export * from './revision';

View file

@ -887,7 +887,7 @@ are-we-there-yet@~1.1.2:
"argo-ui@https://github.com/argoproj/argo-ui.git":
version "1.0.0"
resolved "https://github.com/argoproj/argo-ui.git#7c6a57447d54b2487609e727132e188678b43106"
resolved "https://github.com/argoproj/argo-ui.git#f12c7f443d8108289276feafe47d0161c9de2390"
dependencies:
"@fortawesome/fontawesome-free" "^5.8.1"
"@tippy.js/react" "^2.1.2"