Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ NOTE: As semantic versioning states all 0.y.z releases can contain breaking chan
- [#164](https://github.com/kobsio/kobs/pull/164): Improve chart handling across plugins.
- [#167](https://github.com/kobsio/kobs/pull/167): Improve styling across plugins.
- [#169](https://github.com/kobsio/kobs/pull/169): Rework home page to include plugins, applications and teams.
- [#173](https://github.com/kobsio/kobs/pull/173): Move CRD interfaces to core plugin, so that we can use them within the plugin.

## [v0.5.0](https://github.com/kobsio/kobs/releases/tag/v0.5.0) (2021-08-03)

Expand Down
10 changes: 8 additions & 2 deletions plugins/applications/src/components/home/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,14 @@ import {
import { QueryObserverResult, useQuery } from 'react-query';
import React, { useContext, useState } from 'react';

import { ClustersContext, IClusterContext, IPluginPageProps, LinkWrapper, useDebounce } from '@kobsio/plugin-core';
import { IApplication } from '../../utils/interfaces';
import {
ClustersContext,
IApplication,
IClusterContext,
IPluginPageProps,
LinkWrapper,
useDebounce,
} from '@kobsio/plugin-core';

const Home: React.FunctionComponent<IPluginPageProps> = () => {
const [searchTerm, setSearchTerm] = useState<string>('');
Expand Down
3 changes: 1 addition & 2 deletions plugins/applications/src/components/page/Application.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@ import { QueryObserverResult, useQuery } from 'react-query';
import React, { useState } from 'react';
import { UsersIcon } from '@patternfly/react-icons';

import { ExternalLink, Title } from '@kobsio/plugin-core';
import { ExternalLink, IApplication, Title } from '@kobsio/plugin-core';
import { DashboardsWrapper } from '@kobsio/plugin-dashboards';
import { IApplication } from '../../utils/interfaces';

interface IApplicationsParams {
cluster: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@ import { QueryObserverResult, useQuery } from 'react-query';
import React, { memo } from 'react';
import { useHistory } from 'react-router-dom';

import { IApplication, IReference } from '../../utils/interfaces';
import { IApplication, IApplicationReference, IPluginTimes } from '@kobsio/plugin-core';
import ApplicationsGalleryItem from './ApplicationsGalleryItem';
import { IPluginTimes } from '@kobsio/plugin-core';

interface IApplicationsGalleryProps {
clusters: string[];
namespaces: string[];
team?: IReference;
team?: IApplicationReference;
}

// ApplicationsGallery is the component to display all applications inside a gallery view.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { Badge, Card, CardBody, CardTitle } from '@patternfly/react-core';
import React from 'react';

import { IPluginTimes, LinkWrapper, PluginPreview } from '@kobsio/plugin-core';
import { IApplication } from '../../utils/interfaces';
import { IApplication, IPluginTimes, LinkWrapper, PluginPreview } from '@kobsio/plugin-core';

interface IApplicationsGalleryItemProps {
times: IPluginTimes;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@ import { TopologyIcon, UsersIcon } from '@patternfly/react-icons';
import { Link } from 'react-router-dom';
import React from 'react';

import { ExternalLink, Title } from '@kobsio/plugin-core';
import { ExternalLink, IApplication, Title } from '@kobsio/plugin-core';
import { DashboardsWrapper } from '@kobsio/plugin-dashboards';
import DetailsLink from './DetailsLink';
import { IApplication } from '../../../utils/interfaces';

interface IDetailsProps {
application: IApplication;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import React, { useEffect, useState } from 'react';
import { useLocation } from 'react-router-dom';

import { DrawerLink } from '@kobsio/plugin-core';
import { IApplication } from '../../../utils/interfaces';
import { DrawerLink, IApplication } from '@kobsio/plugin-core';

interface IDetailsLinkProps {
application: IApplication;
Expand Down
38 changes: 2 additions & 36 deletions plugins/applications/src/utils/interfaces.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,6 @@
import { IDashboardReference, IPlugin } from '@kobsio/plugin-dashboards';
import cytoscape from 'cytoscape';

// IApplication implements the Application CR, which can be created by a user to describe an application. While we have
// to omit the cluster, namespace and name field in the Go implementation of the CR, we can assume that these fields are
// present in the frontend, because they will always be set when an application is returned from the Kubernetes API.
export interface IApplication {
cluster: string;
namespace: string;
name: string;
description?: string;
tags?: string[];
links?: ILink[];
teams?: IReference[];
dependencies?: IReference[];
preview?: IPreview;
dashboards?: IDashboardReference[];
}

export interface IPreview {
title: string;
plugin: IPlugin;
}

export interface ILink {
title: string;
link: string;
}

// IReference is the interface, which is used to create a reference to an team or an application. Will the team can be
// used to describe the ownership of the application, the application references are used to identify dependencies.
export interface IReference {
cluster?: string;
namespace?: string;
name: string;
description?: string;
}
import { IApplication, IApplicationReference } from '@kobsio/plugin-core';

// TView are the two options we have to present a list of applications to the user. This can be a gallery view, where
// it will be possible add a single plugin to the card or the topology view, which can be used to display the
Expand All @@ -47,7 +13,7 @@ export interface IPanelOptions {
view?: TView;
clusters?: string[];
namespaces?: string[];
team?: IReference;
team?: IApplicationReference;
}

// INode is a single node for the topology graph. It implements the ElementDefinition interface from cytoscape.
Expand Down
34 changes: 0 additions & 34 deletions plugins/core/src/components/app/Account.tsx

This file was deleted.

4 changes: 2 additions & 2 deletions plugins/core/src/components/app/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import '@patternfly/patternfly/patternfly-addons.css';
import { IPluginComponents, PluginsContextProvider } from '../../context/PluginsContext';
import { AuthContextProvider } from '../../context/AuthContext';
import { ClustersContextProvider } from '../../context/ClustersContext';
import HomePage from './HomePage';
import Home from './Home';
import { PluginPage } from '../plugin/PluginPage';
import { TerminalsContextProvider } from '../../context/TerminalsContext';

Expand Down Expand Up @@ -50,7 +50,7 @@ export const App: React.FunctionComponent<IAppProps> = ({ plugins }: IAppProps)
<Router>
<Page header={Header}>
<Switch>
<Route exact={true} path="/" component={HomePage} />
<Route exact={true} path="/" component={Home} />
<Route exact={false} path="/:name" component={PluginPage} />
</Switch>
</Page>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import {
Divider,
Avatar,
Card,
CardBody,
Grid,
GridItem,
Menu,
Expand All @@ -14,8 +16,9 @@ import { useHistory, useLocation } from 'react-router-dom';

import { AuthContext, IAuthContext } from '../../context/AuthContext';
import { IPluginsContext, PluginsContext } from '../../context/PluginsContext';
import Account from './Account';
import Plugins from './Plugins';
import Account from './account/Account';
import Plugins from './plugins/Plugins';
import { getGravatarImageUrl } from '../../utils/gravatar';

const HomePage: React.FunctionComponent = () => {
const history = useHistory();
Expand Down Expand Up @@ -57,6 +60,29 @@ const HomePage: React.FunctionComponent = () => {
<PageSection variant={PageSectionVariants.default}>
<Grid hasGutter={true}>
<GridItem sm={12} md={12} lg={3} xl={2} xl2={2}>
{authContext.user.hasProfile && (
<React.Fragment>
<Card
style={{ cursor: 'pointer' }}
isCompact={true}
isHoverable={true}
onClick={(): void => changeActivePage(undefined, 'account')}
>
<CardBody>
<div className="pf-u-text-align-center">
<Avatar
src={getGravatarImageUrl(authContext.user.profile.email, 64)}
alt={authContext.user.profile.fullName}
style={{ height: '64px', width: '64px' }}
/>
<div className="pf-c-title pf-m-xl">{authContext.user.profile.fullName}</div>
<div className="pf-u-font-size-md pf-u-color-400">{authContext.user.profile.position}</div>
</div>
</CardBody>
</Card>
<p>&nbsp;</p>
</React.Fragment>
)}
<Menu activeItemId={activePage} onSelect={changeActivePage}>
<MenuContent>
<MenuList>
Expand All @@ -66,12 +92,6 @@ const HomePage: React.FunctionComponent = () => {
{plugin.displayName}
</MenuItem>
))}
{authContext.user.hasProfile && (
<React.Fragment>
<Divider component="li" />
<MenuItem itemId="account">My Account</MenuItem>
</React.Fragment>
)}
</MenuList>
</MenuContent>
</Menu>
Expand Down
34 changes: 34 additions & 0 deletions plugins/core/src/components/app/account/Account.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Avatar, Card, CardBody } from '@patternfly/react-core';
import React, { useContext } from 'react';

import { AuthContext, IAuthContext } from '../../../context/AuthContext';
import AccountTeams from './AccountTeams';
import { getGravatarImageUrl } from '../../../utils/gravatar';

const Account: React.FunctionComponent = () => {
const authContext = useContext<IAuthContext>(AuthContext);

return (
<React.Fragment>
<Card isCompact={true}>
<CardBody>
<div className="pf-u-text-align-center">
<Avatar
src={getGravatarImageUrl(authContext.user.profile.email, 64)}
alt={authContext.user.profile.fullName}
style={{ height: '64px', width: '64px' }}
/>
<div className="pf-c-title pf-m-xl">{authContext.user.profile.fullName}</div>
<div className="pf-u-font-size-md pf-u-color-400">{authContext.user.profile.position}</div>
</div>
</CardBody>
</Card>

<p>&nbsp;</p>

{authContext.user.profile.teams && <AccountTeams user={authContext.user.profile} />}
</React.Fragment>
);
};

export default Account;
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import { Gallery, GalleryItem, PageSection, PageSectionVariants } from '@patternfly/react-core';
import { Gallery, GalleryItem } from '@patternfly/react-core';
import React from 'react';
import { useQuery } from 'react-query';

import { IAuthProfile, IAuthProfileTeam } from '../../context/AuthContext';
import AccountTeamsItem from './AccountTeamsItem';
import { ITeam } from '../../../crds/team';
import { IUser } from '../../../crds/user';

export interface IAccountTeamsProps {
user: IAuthProfile;
user: IUser;
}

const AccountTeams: React.FunctionComponent<IAccountTeamsProps> = ({ user }: IAccountTeamsProps) => {
const { isError, isLoading, data } = useQuery<IAuthProfileTeam[], Error>(['users/teams', user], async () => {
const { isError, isLoading, data } = useQuery<ITeam[], Error>(['users/teams', user], async () => {
try {
const response = await fetch(`/api/plugins/users/teams?cluster=${user.cluster}&namespace=${user.namespace}`, {
body: JSON.stringify({
Expand Down Expand Up @@ -39,21 +40,19 @@ const AccountTeams: React.FunctionComponent<IAccountTeamsProps> = ({ user }: IAc
}

return (
<PageSection variant={PageSectionVariants.default}>
<Gallery hasGutter={true}>
{data.map((team, index) => (
<GalleryItem key={index}>
<AccountTeamsItem
cluster={team.cluster}
namespace={team.namespace}
name={team.name}
description={team.description}
logo={team.logo}
/>
</GalleryItem>
))}
</Gallery>
</PageSection>
<Gallery hasGutter={true}>
{data.map((team, index) => (
<GalleryItem key={index}>
<AccountTeamsItem
cluster={team.cluster}
namespace={team.namespace}
name={team.name}
description={team.description}
logo={team.logo}
/>
</GalleryItem>
))}
</Gallery>
);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Avatar, Card, CardBody, CardHeader, CardTitle } from '@patternfly/react-core';
import React from 'react';

import { LinkWrapper } from '../misc/LinkWrapper';
import teamsIcon from '../../assets/teamsIcon.png';
import { LinkWrapper } from '../../misc/LinkWrapper';
import teamsIcon from '../../../assets/teamsIcon.png';

interface IAccountTeamsItemProps {
cluster: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Card, CardBody, CardHeader, CardTitle } from '@patternfly/react-core';
import React, { useContext } from 'react';

import { IPluginData, IPluginsContext, PluginsContext } from '../../context/PluginsContext';
import { LinkWrapper } from '../misc/LinkWrapper';
import { IPluginData, IPluginsContext, PluginsContext } from '../../../context/PluginsContext';
import { LinkWrapper } from '../../misc/LinkWrapper';

// IPluginItemProps is the interface for an item on the home page. Each item contains a title, body, link and icon.
interface IPluginItemProps {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Gallery, GalleryItem } from '@patternfly/react-core';
import React, { useContext } from 'react';

import { AuthContext, IAuthContext } from '../../context/AuthContext';
import { IPluginData } from '../../context/PluginsContext';
import { AuthContext, IAuthContext } from '../../../context/AuthContext';
import { IPluginData } from '../../../context/PluginsContext';
import PluginItem from './PluginItem';

export interface IPluginsProps {
Expand Down
Loading