Skip to content

Commit

Permalink
Merge pull request #32 from mfrances17/details-ui
Browse files Browse the repository at this point in the history
Details/Activity tabs, various other functionality
  • Loading branch information
dlabaj authored May 1, 2020
2 parents c96e0dc + 68e022d commit f0fd631
Show file tree
Hide file tree
Showing 20 changed files with 268 additions and 108 deletions.
25 changes: 23 additions & 2 deletions packages/services/src/api-services/api-services.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Api} from "@apicurio/models";
import {Api, ApiCollaborator} from "@apicurio/models";
import {AbstractHubService} from "./hub";
import {ConfigService} from "../config/config.service";
import {IAuthenticationService} from "../authentication/auth.service";
Expand All @@ -10,6 +10,7 @@ import { AxiosRequestConfig } from "axios";
*/
export class ApisService extends AbstractHubService {
private cachedApis: Api[] = null;
private cachedCollaborators: ApiCollaborator[] = null;

/**
* Constructor.
Expand All @@ -20,6 +21,25 @@ export class ApisService extends AbstractHubService {
super(authService, config);
}

/**
* @see ApisService.getCollaborators
*/
public getCollaborators(apiId: string): Promise<ApiCollaborator[]> {
console.info("[ApisService] Getting collaborators for API Design %s", apiId);

let getCollaboratorsUrl: string = this.endpoint("/designs/:designId/collaborators", {
designId: apiId
});
let options: any = this.options({ "Accept": "application/json" });

console.info("[ApisService] Fetching collaborator list: %s", getCollaboratorsUrl);
return this.httpGet<ApiCollaborator[]>(getCollaboratorsUrl, options, (resp) => {
this.cachedCollaborators = resp as ApiCollaborator[];
console.log(`api-services: cachedCollaborators = ${this.cachedCollaborators}`);
return this.cachedCollaborators;
});
}

// Gets all APIs
public getApis(): Promise<Api[]> {
console.info("[ApisService] Getting all APIs");
Expand All @@ -29,7 +49,8 @@ export class ApisService extends AbstractHubService {

console.info("[ApisService] Fetching API list: %s", listApisUrl);
return this.httpGet<Api[]>(listApisUrl, options, (resp) => {
this.cachedApis = resp.data as Api[];
this.cachedApis = resp as Api[];
// this.getCollaborators(this.cachedApis[0].id).then( (value: ApiCollaborator[]) => {debugger;});
return this.cachedApis;
})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export class CurrentUserService extends AbstractHubService {

console.info("[CurrentUserService] Fetching user activity: %s", activityUrl);
return this.httpGet<ApiDesignChange[]>(activityUrl, options, (resp) => {
return resp.data as ApiDesignChange[];
return resp as ApiDesignChange[];
});
}
}
4 changes: 2 additions & 2 deletions packages/services/src/api-services/hub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,10 @@ export abstract class AbstractHubService {
return axios.request(config)
.then(response => {
if (successCallback) {
return successCallback(response);
return successCallback(response.data);
}
else {
return response;
return response.data;
}
})
.catch(error => console.log(error)); // handle error state
Expand Down
1 change: 0 additions & 1 deletion packages/studio/src/app/appHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ export const AppHeader = () => {
const setNotificationDrawerState = (notificationDrawerState: boolean) => {
globalContext.setNotificationDrawerExpanded(!notificationDrawerState);
}


const [isKebabDropdownOpen, setKebabDropdown] = useState(false);
const [isKebabDropdownMdOpen, setKebabDropdownMd] = useState(false);
Expand Down
6 changes: 3 additions & 3 deletions packages/studio/src/app/common/appConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export class Services {

private static singleton: Services;
public configService: ConfigService = new ConfigService();
public autheticationService : KeycloakAuthenticationService = new KeycloakAuthenticationService(this.configService);
public apisService: ApisService = new ApisService(this.autheticationService, this.configService);
public currentUserService: CurrentUserService = new CurrentUserService(this.autheticationService, this.configService);
public authenticationService : KeycloakAuthenticationService = new KeycloakAuthenticationService(this.configService);
public apisService: ApisService = new ApisService(this.authenticationService, this.configService);
public currentUserService: CurrentUserService = new CurrentUserService(this.authenticationService, this.configService);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React from 'react';
import { DataList, DataListItem, DataListItemRow, DataListItemCells, DataListCell } from '@patternfly/react-core';
import { ApiActivityItem } from '../apiActivityItem/apiActivityItem';
import { GlobalContext } from '../../../../context';

export interface ApiActivityViewProps {
currentApi: any
}

function findId(apis: any[], id: string) {
console.log(`array is ${JSON.stringify(apis)}, id is ${id}`);
const apiTemp = apis.find(api => api.apiId === id);
if (apiTemp !== undefined) {
return apiTemp;
}
else {
return Error;
}
}

export const ApiActivityView = (props) => {
const { recentActivity } = { ... React.useContext(GlobalContext).store };
const selectedApi = props.currentApi.id;
let specificApiActivity = [];

specificApiActivity = findId(recentActivity, selectedApi);

const noActivityMsg = "No activity found for this API.";


return (
<React.Fragment>
<div className="api-details-content">
<h3>Activity</h3>
{ specificApiActivity !== Error ? recentActivity.map((activity, index) =>
<DataList aria-label="app-data-list-api-activity" key="api-activity-list">
<React.Fragment>
<DataListItem aria-labelledby={`data-list-item-${index}`} key={index}>
<DataListItemRow>
<DataListItemCells
dataListCells={[
<DataListCell key="1">
<ApiActivityItem
activityApiName={activity.apiName}
activityType={activity.type}
activityOn={activity.on}
activityData={activity.data}
/>
</DataListCell>
]}/>
</DataListItemRow>
</DataListItem>
</React.Fragment>
</DataList>
) :
<p>{noActivityMsg}</p>}
</div>
</React.Fragment>
)
}

export default ApiActivityView;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './apiActivityView';
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import React from 'react';
import React, { useContext } from 'react';
import { Gallery } from '@patternfly/react-core';
import {ApiCard} from './apiCard';
import data from '../../../../api-data.json';
import { GlobalContext } from '../../../../context';

export const ApiCardView: React.FunctionComponent<any> = (props) => {
const apiData = data.apis;
const cardList = apiData.map((api, index) =>
const { apis } = {... useContext(GlobalContext).store}

const cardList = apis.map((api, index) =>
<ApiCard
key={index}
id={api.id}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@ import React from 'react';
import {DataList} from '@patternfly/react-core';
import ApiDataListItem from './apiDataListItem';

interface AppDataListProps {
interface ApiDataListProps {
viewDetails: React.MouseEventHandler,
selectItem: FunctionStringCallback,
keyListItem: FunctionStringCallback
}

interface AppDataListState {
interface ApiDataListState {
selectedDataListItemId: string
}

class AppDataList extends React.Component<AppDataListProps, AppDataListState> {
constructor(props: AppDataListProps) {
class ApiDataList extends React.Component<ApiDataListProps, ApiDataListState> {
constructor(props: ApiDataListProps) {
super(props);
this.state = {
selectedDataListItemId: ''
Expand All @@ -33,10 +33,10 @@ class AppDataList extends React.Component<AppDataListProps, AppDataListState> {
selectedDataListItemId={this.state.selectedDataListItemId}
onSelectDataListItem={this.onSelectDataListItem}
>
<ApiDataListItem/>
<ApiDataListItem />
</DataList>
);
}
}

export default AppDataList;
export default ApiDataList;
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import React, { useEffect, useContext } from 'react';
import React, { useContext } from 'react';
import { Button, DataListItem, DataListItemCells, DataListItemRow, DataListCell, DataListCheck, DataListAction } from '@patternfly/react-core';
import {ApiTag} from '../apiTag';
import {ApiDropdownKebab} from '../apiDropDownKebab';
import ApicurioIcon from '../../../assets/apicurio-icon.png';
import './apiDataListItem.css';
import { GlobalContext } from '../../../../context';
import { GlobalContext, GlobalContextObj } from '../../../../context';

export const ApiDataListItem = () => {

const { apis } = {... useContext(GlobalContext).store}
const globalContext: GlobalContextObj = useContext(GlobalContext);
const setApiDrawerState = (apiDrawerState: boolean, currentApiId: string) => {
globalContext.setApiDrawerExpanded(!apiDrawerState);
}

return (
<React.Fragment>
Expand Down Expand Up @@ -37,7 +40,7 @@ export const ApiDataListItem = () => {
]}
/>
<DataListAction aria-labelledby={`data-list-item-${api.id}`} id={`data-list-item-${api.id}`} aria-label="Actions">
<Button variant="link">View Details</Button>
<Button variant="link" onClick={() => setApiDrawerState(globalContext.store.apiDrawerExpanded)}>View Details</Button>
<Button variant="secondary">Edit API</Button>
<ApiDropdownKebab/>
</DataListAction>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
div span {
padding-bottom: var(--pf-global--spacer--sm);
margin-left: 16px;
}
div h3 {
font-weight: bold;
margin-top: var(--pf-global--spacer--md);
margin-bottom: var(--pf-global--spacer--sm);
}

.api-details-content {
padding-left: var(--pf-global--spacer--md); /* remove this when new drawer styles in pf are added */
}

.app-details-content.heading {
padding-bottom: var(--pf-global--spacer--sm);
margin-left: 16px;
}
.api-details-content-body {
padding: 0 !important;
}

.api-details-content-body .pf-c-drawer__panel-body {
padding: 0;
}

.app-details-content-icon-text {
padding-bottom: var(--pf-global--spacer--sm);
margin-left: 16px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react';
import { UserIcon, UsersIcon, OutlinedClockIcon } from '@patternfly/react-icons';
import './apiDetailsView.css';
import moment from "moment";

export interface ApiDetailsViewProps {
currentApi: any
}

export const ApiDetailsView: React.FunctionComponent<ApiDetailsViewProps> = (props) => {
const createdOn = props.currentApi.createdOn;
const createdBy = props.currentApi.createdBy;

return (
<React.Fragment>
<div className="api-details-content">
<h3>Details</h3>
<p><OutlinedClockIcon /><span>Created on {moment(createdOn).format('MMM DD, YYYY')}</span></p>
<p><UserIcon /><span>Created by {createdBy}</span></p>
<p><UsersIcon /><span>? Other collaborators</span></p>
<br />
<h3>Collaborators</h3>
</div>
</React.Fragment>
);
}

export default ApiDetailsView;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './apiDetailsView';
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,8 @@

.api-drawer-panel-body .pf-c-drawer__panel-body {
padding: 0;
}

.api-drawer-panel-button {
margin-right: 4px;
}
50 changes: 20 additions & 30 deletions packages/studio/src/app/components/api/apiDrawer/apiDrawer.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React from 'react';
import React, { useContext } from 'react';
import { Drawer, DrawerPanelContent, DrawerContent } from '@patternfly/react-core/dist/esm/experimental';
import AppDataList from '../apiDataList/apiDataList';
import ApiDataList from '../apiDataList/apiDataList';
import {ApiCardView} from '../..';
import ApiDrawerPanelContent from './apiDrawerPanelContent';
import { GlobalContext, GlobalContextObj } from '../../../../context';
import './apiDrawer.css';

export interface ApiDrawerProps {
Expand All @@ -14,53 +15,42 @@ interface ApiDrawerState {
readonly isExpanded: boolean,
}

export class ApiDrawer extends React.Component<ApiDrawerProps, ApiDrawerState> {
constructor(props: ApiDrawerProps) {
super(props);
this.state = {
currentApiId: "",
isExpanded: false
};
export const ApiDrawer: React.FunctionComponent<ApiDrawerProps> = (props) => {
const globalContext: GlobalContextObj = useContext(GlobalContext);
const { apiDrawerExpanded } = {... useContext(GlobalContext).store};
const setSelectedApiState = (selectedApiState: string) => {
globalContext.setSelectedApiId(selectedApiState);
}

render() {
const { isExpanded, currentApiId } = this.state;
function openDrawer() {
const isExpanded = !apiDrawerExpanded;
};

function findKey(id: string) {
const keyListItem = id;
setSelectedApiState(keyListItem);
}

return (
<React.Fragment>
<Drawer isExpanded={isExpanded} isInline className="app-drawer-drawer">
<Drawer isExpanded={apiDrawerExpanded} isInline className="app-drawer-drawer">
<DrawerContent>
<div className="api-drawer-content">
{
this.props.dashboardView === 'list' ? (
<AppDataList keyListItem={this.findKey} selectItem={this.openDrawer} viewDetails={this.openDrawer}/>
props.dashboardView === 'list' ? (
<ApiDataList keyListItem={findKey} selectItem={setSelectedApiState} viewDetails={openDrawer}/>
) : (
<ApiCardView/>
)
}
</div>
</DrawerContent>
<DrawerPanelContent className="api-drawer-panel-body">
<ApiDrawerPanelContent currentApiId={currentApiId}/>
<ApiDrawerPanelContent />
</DrawerPanelContent>
</Drawer>
</React.Fragment>
);
}

private openDrawer = () => {
const isExpanded = !this.state.isExpanded;
this.setState({
isExpanded
});
};

private findKey = (id: string) => {
const keyListItem = id;
this.setState({
currentApiId: keyListItem
})
}
}

export default ApiDrawer;
Loading

0 comments on commit f0fd631

Please sign in to comment.