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

fix: hide app namespace on the ui #11247

Merged
merged 10 commits into from
Nov 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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
ashutosh16 marked this conversation as resolved.
Show resolved Hide resolved
? `(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