Skip to content

Commit

Permalink
fix: hide app namespace on the ui (argoproj#11111) (argoproj#11247)
Browse files Browse the repository at this point in the history
* fix: hide app namespace when irrelevant (argoproj#11111)

Signed-off-by: Michael Crenshaw <[email protected]>

* wire up setting

Signed-off-by: Michael Crenshaw <[email protected]>

* fix: hide app namespace

Signed-off-by: ashutosh16 <[email protected]>

* fix: hide app namespace

Signed-off-by: ashutosh16 <[email protected]>

* add null check

Signed-off-by: ashutosh16 <[email protected]>

* Update ui/src/app/applications/components/utils.tsx

Co-authored-by: Blake Pettersson <[email protected]>
Signed-off-by: asingh <[email protected]>

* lint

Signed-off-by: ashutosh16 <[email protected]>

* fix name generation

Signed-off-by: Michael Crenshaw <[email protected]>

Signed-off-by: Michael Crenshaw <[email protected]>
Signed-off-by: ashutosh16 <[email protected]>
Signed-off-by: asingh <[email protected]>
Co-authored-by: Michael Crenshaw <[email protected]>
Co-authored-by: Blake Pettersson <[email protected]>
  • Loading branch information
3 people authored Nov 21, 2022
1 parent 437cd4f commit 15b0785
Show file tree
Hide file tree
Showing 12 changed files with 223 additions and 153 deletions.
3 changes: 3 additions & 0 deletions assets/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -4097,6 +4097,9 @@
"appLabelKey": {
"type": "string"
},
"appsInAnyNamespaceEnabled": {
"type": "boolean"
},
"configManagementPlugins": {
"type": "array",
"items": {
Expand Down
222 changes: 133 additions & 89 deletions pkg/apiclient/settings/settings.pb.go

Large diffs are not rendered by default.

9 changes: 5 additions & 4 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package server

import (
"context"
netCtx "context"
"crypto/tls"
"fmt"
goio "io"
Expand All @@ -24,8 +25,6 @@ import (
// nolint:staticcheck
golang_proto "github.com/golang/protobuf/proto"

netCtx "context"

"github.com/argoproj/notifications-engine/pkg/api"
"github.com/argoproj/pkg/sync"
"github.com/go-redis/redis/v8"
Expand Down Expand Up @@ -61,6 +60,8 @@ import (
accountpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/account"
applicationpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/application"

"github.com/pkg/errors"

applicationsetpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/applicationset"
certificatepkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/certificate"
clusterpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/cluster"
Expand Down Expand Up @@ -121,7 +122,6 @@ import (
"github.com/argoproj/argo-cd/v2/util/swagger"
tlsutil "github.com/argoproj/argo-cd/v2/util/tls"
"github.com/argoproj/argo-cd/v2/util/webhook"
"github.com/pkg/errors"
)

const maxConcurrentLoginRequestsCountEnv = "ARGOCD_MAX_CONCURRENT_LOGIN_REQUESTS_COUNT"
Expand Down Expand Up @@ -733,7 +733,8 @@ func (a *ArgoCDServer) newGRPCServer() (*grpc.Server, application.AppResourceTre

applicationSetService := applicationset.NewServer(a.db, a.KubeClientset, a.enf, a.Cache, a.AppClientset, a.appLister, a.appsetInformer, a.appsetLister, a.projLister, a.settingsMgr, a.Namespace, projectLock)
projectService := project.NewServer(a.Namespace, a.KubeClientset, a.AppClientset, a.enf, projectLock, a.sessionMgr, a.policyEnforcer, a.projInformer, a.settingsMgr, a.db)
settingsService := settings.NewServer(a.settingsMgr, a, a.DisableAuth)
appsInAnyNamespaceEnabled := len(a.ArgoCDServerOpts.ApplicationNamespaces) > 0
settingsService := settings.NewServer(a.settingsMgr, a, a.DisableAuth, appsInAnyNamespaceEnabled)
accountService := account.NewServer(a.sessionMgr, a.settingsMgr, a.enf)

notificationService := notification.NewServer(a.apiFactory)
Expand Down
27 changes: 15 additions & 12 deletions server/settings/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package settings

import (
"context"

"github.com/ghodss/yaml"

sessionmgr "github.com/argoproj/argo-cd/v2/util/session"
Expand All @@ -13,18 +14,19 @@ import (

// Server provides a Settings service
type Server struct {
mgr *settings.SettingsManager
authenticator Authenticator
disableAuth bool
mgr *settings.SettingsManager
authenticator Authenticator
disableAuth bool
appsInAnyNamespaceEnabled bool
}

type Authenticator interface {
Authenticate(ctx context.Context) (context.Context, error)
}

// NewServer returns a new instance of the Settings service
func NewServer(mgr *settings.SettingsManager, authenticator Authenticator, disableAuth bool) *Server {
return &Server{mgr: mgr, authenticator: authenticator, disableAuth: disableAuth}
func NewServer(mgr *settings.SettingsManager, authenticator Authenticator, disableAuth, appsInAnyNamespaceEnabled bool) *Server {
return &Server{mgr: mgr, authenticator: authenticator, disableAuth: disableAuth, appsInAnyNamespaceEnabled: appsInAnyNamespaceEnabled}
}

// Get returns Argo CD settings
Expand Down Expand Up @@ -102,13 +104,14 @@ func (s *Server) Get(ctx context.Context, q *settingspkg.SettingsQuery) (*settin
ChatText: help.ChatText,
BinaryUrls: help.BinaryURLs,
},
Plugins: plugins,
UserLoginsDisabled: userLoginsDisabled,
KustomizeVersions: kustomizeVersions,
UiCssURL: argoCDSettings.UiCssURL,
PasswordPattern: argoCDSettings.PasswordPattern,
TrackingMethod: trackingMethod,
ExecEnabled: argoCDSettings.ExecEnabled,
Plugins: plugins,
UserLoginsDisabled: userLoginsDisabled,
KustomizeVersions: kustomizeVersions,
UiCssURL: argoCDSettings.UiCssURL,
PasswordPattern: argoCDSettings.PasswordPattern,
TrackingMethod: trackingMethod,
ExecEnabled: argoCDSettings.ExecEnabled,
AppsInAnyNamespaceEnabled: s.appsInAnyNamespaceEnabled,
}

if sessionmgr.LoggedIn(ctx) || s.disableAuth {
Expand Down
1 change: 1 addition & 0 deletions server/settings/settings.proto
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ message Settings {
string statusBadgeRootUrl = 21;
bool execEnabled = 22;
string controllerNamespace = 23;
bool appsInAnyNamespaceEnabled = 24;
}

message GoogleAnalyticsConfig {
Expand Down
88 changes: 47 additions & 41 deletions ui/src/app/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ import login from './login';
import settings from './settings';
import {Layout} from './shared/components/layout/layout';
import {VersionPanel} from './shared/components/version-info/version-info-panel';
import {Provider} from './shared/context';
import {AuthSettingsCtx, Provider} from './shared/context';
import {services} from './shared/services';
import requests from './shared/services/requests';
import {hashCode} from './shared/utils';
import {Banner} from './ui-banner/ui-banner';
import userInfo from './user-info';
import {AuthSettings} from './shared/models';

services.viewPreferences.init();
const bases = document.getElementsByTagName('base');
Expand Down Expand Up @@ -71,8 +72,8 @@ const versionLoader = services.version.version();
async function isExpiredSSO() {
try {
const {iss} = await services.users.get();
const authSettings = React.useContext(AuthSettingsCtx);
if (iss && iss !== 'argocd') {
const authSettings = await services.authService.settings();
return ((authSettings.dexConfig && authSettings.dexConfig.connectors) || []).length > 0 || authSettings.oidcConfig;
}
} catch {
Expand Down Expand Up @@ -106,7 +107,10 @@ requests.onError.subscribe(async err => {
}
});

export class App extends React.Component<{}, {popupProps: PopupProps; showVersionPanel: boolean; error: Error; navItems: NavItem[]; routes: Routes; extensionsLoaded: boolean}> {
export class App extends React.Component<
{},
{popupProps: PopupProps; showVersionPanel: boolean; error: Error; navItems: NavItem[]; routes: Routes; extensionsLoaded: boolean; authSettings: AuthSettings}
> {
public static childContextTypes = {
history: PropTypes.object,
apis: PropTypes.object
Expand All @@ -124,7 +128,7 @@ export class App extends React.Component<{}, {popupProps: PopupProps; showVersio

constructor(props: {}) {
super(props);
this.state = {popupProps: null, error: null, showVersionPanel: false, navItems: [], routes: null, extensionsLoaded: false};
this.state = {popupProps: null, error: null, showVersionPanel: false, navItems: [], routes: null, extensionsLoaded: false, authSettings: null};
this.popupManager = new PopupManager();
this.notificationsManager = new NotificationsManager();
this.navigationManager = new NavigationManager(history);
Expand Down Expand Up @@ -181,7 +185,7 @@ export class App extends React.Component<{}, {popupProps: PopupProps; showVersio
};
}

this.setState({...this.state, navItems: extendedNavItems, routes: extendedRoutes, extensionsLoaded: true});
this.setState({...this.state, navItems: extendedNavItems, routes: extendedRoutes, extensionsLoaded: true, authSettings});
}

public render() {
Expand Down Expand Up @@ -211,42 +215,44 @@ export class App extends React.Component<{}, {popupProps: PopupProps; showVersio
<PageContext.Provider value={{title: 'Argo CD'}}>
<Provider value={{history, popup: this.popupManager, notifications: this.notificationsManager, navigation: this.navigationManager, baseHref: base}}>
{this.state.popupProps && <Popup {...this.state.popupProps} />}
<Router history={history}>
<Switch>
<Redirect exact={true} path='/' to='/applications' />
{Object.keys(this.routes).map(path => {
const route = this.routes[path];
return (
<Route
key={path}
path={path}
render={routeProps =>
route.noLayout ? (
<div>
<route.component {...routeProps} />
</div>
) : (
<DataLoader load={() => services.viewPreferences.getPreferences()}>
{pref => (
<Layout
onVersionClick={() => this.setState({showVersionPanel: true})}
navItems={this.navItems}
pref={pref}
isExtension={route.extension}>
<Banner>
<route.component {...routeProps} />
</Banner>
</Layout>
)}
</DataLoader>
)
}
/>
);
})}
{this.state.extensionsLoaded && <Redirect path='*' to='/' />}
</Switch>
</Router>
<AuthSettingsCtx.Provider value={this.state.authSettings}>
<Router history={history}>
<Switch>
<Redirect exact={true} path='/' to='/applications' />
{Object.keys(this.routes).map(path => {
const route = this.routes[path];
return (
<Route
key={path}
path={path}
render={routeProps =>
route.noLayout ? (
<div>
<route.component {...routeProps} />
</div>
) : (
<DataLoader load={() => services.viewPreferences.getPreferences()}>
{pref => (
<Layout
onVersionClick={() => this.setState({showVersionPanel: true})}
navItems={this.navItems}
pref={pref}
isExtension={route.extension}>
<Banner>
<route.component {...routeProps} />
</Banner>
</Layout>
)}
</DataLoader>
)
}
/>
);
})}
{this.state.extensionsLoaded && <Redirect path='*' to='/' />}
</Switch>
</Router>
</AuthSettingsCtx.Provider>
</Provider>
</PageContext.Provider>
<Notifications notifications={this.notificationsManager.notifications} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as classNames from 'classnames';
import * as React from 'react';
import {Key, KeybindingContext, NumKey, NumKeyToNumber, NumPadKey, useNav} from 'argo-ui/v2';
import {Cluster} from '../../../shared/components';
import {Consumer, Context} from '../../../shared/context';
import {Consumer, Context, AuthSettingsCtx} from '../../../shared/context';
import * as models from '../../../shared/models';
import {ApplicationURLs} from '../application-urls';
import * as AppUtils from '../utils';
Expand Down Expand Up @@ -53,6 +53,7 @@ export const ApplicationTiles = ({applications, syncApplication, refreshApplicat
const appRef = {ref: React.useRef(null), set: false};
const appContainerRef = React.useRef(null);
const appsPerRow = useItemsPerContainer(appRef.ref, appContainerRef);
const authSettingsCtx = React.useContext(AuthSettingsCtx);

const {useKeybinding} = React.useContext(KeybindingContext);

Expand Down Expand Up @@ -97,7 +98,6 @@ export const ApplicationTiles = ({applications, syncApplication, refreshApplicat
return navApp(NumKeyToNumber(n));
}
});

return (
<Consumer>
{ctx => (
Expand Down Expand Up @@ -130,7 +130,9 @@ export const ApplicationTiles = ({applications, syncApplication, refreshApplicat
}>
<i className={'icon argo-icon-' + (app.spec.source.chart != null ? 'helm' : 'git')} />
<Tooltip content={AppUtils.appInstanceName(app)}>
<span className='applications-list__title'>{AppUtils.appQualifiedName(app)}</span>
<span className='applications-list__title'>
{AppUtils.appQualifiedName(app, authSettingsCtx?.appsInAnyNamespaceEnabled)}
</span>
</Tooltip>
</div>
<div
Expand Down
4 changes: 2 additions & 2 deletions ui/src/app/applications/components/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1150,8 +1150,8 @@ export const urlPattern = new RegExp(
)
);

export function appQualifiedName(app: appModels.Application): string {
return app.metadata.namespace + '/' + app.metadata.name;
export function appQualifiedName(app: appModels.Application, nsEnabled: boolean): string {
return (nsEnabled ? app.metadata.namespace + '/' : '') + app.metadata.name;
}

export function appInstanceName(app: appModels.Application): string {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import {FormFunctionProps} from 'react-form';
import {CheckboxField} from '..';
import * as models from '../../models';
import {appInstanceName, appQualifiedName, ComparisonStatusIcon, HealthStatusIcon, OperationPhaseIcon} from '../../../applications/components/utils';
import {AuthSettingsCtx} from '../../context';

export const ApplicationSelector = ({apps, formApi}: {apps: models.Application[]; formApi: FormFunctionProps}) => {
const authSettingsCtx = React.useContext(AuthSettingsCtx);
return (
<>
<label>
Expand All @@ -18,7 +20,9 @@ export const ApplicationSelector = ({apps, formApi}: {apps: models.Application[]
<label key={appInstanceName(app)} style={{marginTop: '0.5em', cursor: 'pointer'}}>
<CheckboxField field={`app/${i}`} />
&nbsp;
{app.isAppOfAppsPattern ? `(App of Apps) ${appQualifiedName(app)}` : appQualifiedName(app)}
{app.isAppOfAppsPattern
? `(App of Apps) ${appQualifiedName(app, authSettingsCtx?.appsInAnyNamespaceEnabled)}`
: appQualifiedName(app, authSettingsCtx?.appsInAnyNamespaceEnabled)}
&nbsp;
<ComparisonStatusIcon status={app.status.sync.status} />
&nbsp;
Expand Down
5 changes: 4 additions & 1 deletion ui/src/app/shared/context.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {AppContext as ArgoAppContext, NavigationApi, NotificationsApi, PopupApi} from 'argo-ui';
import {History} from 'history';
import * as React from 'react';
import * as models from './models';

export type AppContext = ArgoAppContext & {apis: {popup: PopupApi; notifications: NotificationsApi; navigation: NavigationApi; baseHref: string}};

Expand All @@ -11,4 +12,6 @@ export interface ContextApis {
baseHref: string;
}
export const Context = React.createContext<ContextApis & {history: History}>(null);
export const {Provider, Consumer} = Context;
export let {Provider, Consumer} = Context;

export const AuthSettingsCtx = React.createContext<models.AuthSettings>(null);
1 change: 1 addition & 0 deletions ui/src/app/shared/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,7 @@ export interface AuthSettings {
uiBannerPermanent: boolean;
uiBannerPosition: string;
execEnabled: boolean;
appsInAnyNamespaceEnabled: boolean;
}

export interface UserInfo {
Expand Down
2 changes: 2 additions & 0 deletions util/settings/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ type ArgoCDSettings struct {
// token verification to pass despite the OIDC provider having an invalid certificate. Only set to `true` if you
// understand the risks.
OIDCTLSInsecureSkipVerify bool `json:"oidcTLSInsecureSkipVerify"`
// AppsInAnyNamespaceEnabled indicates whether applications are allowed to be created in any namespace
AppsInAnyNamespaceEnabled bool `json:"appsInAnyNamespaceEnabled"`
}

type GoogleAnalytics struct {
Expand Down

0 comments on commit 15b0785

Please sign in to comment.