mirror of
https://github.com/argoproj/argo-cd
synced 2026-05-23 09:18:26 +00:00
Improve wrapped text rendering on application list and application sync status pages (#2067)
This commit is contained in:
parent
29b72ca695
commit
dacdeb6025
12 changed files with 114 additions and 58 deletions
|
|
@ -8,4 +8,12 @@
|
|||
left: 15px;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
&__message {
|
||||
white-space: normal;
|
||||
line-height: 16px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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}))'
|
||||
|
|
|
|||
|
|
@ -190,12 +190,6 @@
|
|||
& > .columns:first-child {
|
||||
padding-left: 30px;
|
||||
}
|
||||
& > .columns:last-child {
|
||||
.argo-dropdown {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
margin-left: -30px !important;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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>);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
||||
<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'>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Reference in a new issue