Refactor details-panel
authorDaniel Kos <daniel.kos@contractors.roche.com>
Sun, 22 Jul 2018 23:37:00 +0000 (01:37 +0200)
committerDaniel Kos <daniel.kos@contractors.roche.com>
Sun, 22 Jul 2018 23:38:14 +0000 (01:38 +0200)
No issue #

Arvados-DCO-1.1-Signed-off-by: Daniel Kos <daniel.kos@contractors.roche.com>

16 files changed:
src/components/details-attribute/details-attribute.tsx [moved from src/components/attribute/attribute.tsx with 86% similarity]
src/components/details-panel-factory/details-panel-factory.tsx [deleted file]
src/components/details-panel-factory/items/collection-item.tsx [deleted file]
src/components/details-panel-factory/items/empty-item.tsx [deleted file]
src/components/details-panel-factory/items/process-item.tsx [deleted file]
src/components/details-panel-factory/items/project-item.tsx [deleted file]
src/components/empty-state/empty-state.tsx [deleted file]
src/models/container-request.ts
src/models/details.ts [new file with mode: 0644]
src/models/empty.ts
src/views-components/details-panel/collection-details.tsx [new file with mode: 0644]
src/views-components/details-panel/details-data.tsx [moved from src/components/details-panel-factory/items/abstract-item.tsx with 53% similarity]
src/views-components/details-panel/details-panel.tsx
src/views-components/details-panel/empty-details.tsx [new file with mode: 0644]
src/views-components/details-panel/process-details.tsx [new file with mode: 0644]
src/views-components/details-panel/project-details.tsx [new file with mode: 0644]

similarity index 86%
rename from src/components/attribute/attribute.tsx
rename to src/components/details-attribute/details-attribute.tsx
index e2da980e8cc3facd11366d73b81476196b1ea992..56da6c177cba95484171c55506b67411215021eb 100644 (file)
@@ -33,16 +33,16 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
     }
 });
 
-interface AttributeDataProps {
+interface DetailsAttributeDataProps {
     label: string;
     value?: string | number;
     link?: string;
     children?: React.ReactNode;
 }
 
-type AttributeProps = AttributeDataProps & WithStyles<CssRules>;
+type DetailsAttributeProps = DetailsAttributeDataProps & WithStyles<CssRules>;
 
-export const Attribute = withStyles(styles)(({ label, link, value, children, classes }: AttributeProps) =>
+export const DetailsAttribute = withStyles(styles)(({ label, link, value, children, classes }: DetailsAttributeProps) =>
     <Typography component="div" className={classes.attribute}>
         <Typography component="span" className={classes.label}>{label}</Typography>
         { link
diff --git a/src/components/details-panel-factory/details-panel-factory.tsx b/src/components/details-panel-factory/details-panel-factory.tsx
deleted file mode 100644 (file)
index 9fb8f32..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (C) The Arvados Authors. All rights reserved.
-//
-// SPDX-License-Identifier: AGPL-3.0
-
-import { ProjectItem } from './items/project-item';
-import { CollectionItem } from './items/collection-item';
-import { ProcessItem } from './items/process-item';
-import { AbstractItem } from './items/abstract-item';
-import { EmptyItem } from './items/empty-item';
-import { DetailsPanelResource } from '../../views-components/details-panel/details-panel';
-import { EmptyResource } from '../../models/empty';
-import { ResourceKind } from '../../models/resource';
-
-export class DetailsPanelFactory {
-    static createItem(res: DetailsPanelResource): AbstractItem {
-        switch (res.kind) {
-            case ResourceKind.Project:
-                return new ProjectItem(res);
-            case ResourceKind.Collection:
-                return new CollectionItem(res);
-            case ResourceKind.Process:
-                return new ProcessItem(res);
-            default:
-                return new EmptyItem(res as EmptyResource);
-        }
-    }
-}
diff --git a/src/components/details-panel-factory/items/collection-item.tsx b/src/components/details-panel-factory/items/collection-item.tsx
deleted file mode 100644 (file)
index 5616a6b..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (C) The Arvados Authors. All rights reserved.
-//
-// SPDX-License-Identifier: AGPL-3.0
-
-import * as React from 'react';
-import { CollectionIcon } from '../../icon/icon';
-import { Attribute } from '../../attribute/attribute';
-import { AbstractItem } from './abstract-item';
-import { CollectionResource } from '../../../models/collection';
-import { formatDate } from '../../../common/formatters';
-import { resourceLabel } from '../../../common/labels';
-import { ResourceKind } from '../../../models/resource';
-
-export class CollectionItem extends AbstractItem<CollectionResource> {
-
-    getIcon(className?: string) {
-        return <CollectionIcon className={className} />;
-    }
-
-    buildDetails() {
-        return <div>
-            <Attribute label='Type' value={resourceLabel(ResourceKind.Collection)} />
-            <Attribute label='Size' value='---' />
-            <Attribute label='Owner' value={this.item.ownerUuid} />
-            <Attribute label='Last modified' value={formatDate(this.item.modifiedAt)} />
-            <Attribute label='Created at' value={formatDate(this.item.createdAt)} />
-            {/* Links but we dont have view */}
-            <Attribute label='Collection UUID' link={this.item.uuid} value={this.item.uuid} />
-            <Attribute label='Content address' link={this.item.portableDataHash} value={this.item.portableDataHash} />
-            {/* Missing attrs */}
-            <Attribute label='Number of files' value='20' />
-            <Attribute label='Content size' value='54 MB' />
-        </div>;
-    }
-}
diff --git a/src/components/details-panel-factory/items/empty-item.tsx b/src/components/details-panel-factory/items/empty-item.tsx
deleted file mode 100644 (file)
index b9a4872..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (C) The Arvados Authors. All rights reserved.
-//
-// SPDX-License-Identifier: AGPL-3.0
-
-import * as React from 'react';
-import { DefaultIcon, ProjectsIcon } from '../../icon/icon';
-import { AbstractItem } from './abstract-item';
-import { EmptyState } from '../../empty-state/empty-state';
-import { EmptyResource } from '../../../models/empty';
-
-export class EmptyItem extends AbstractItem<EmptyResource> {
-
-    getIcon(className?: string) {
-        return <ProjectsIcon className={className} />;
-    }
-
-    buildDetails() {
-        return <EmptyState icon={DefaultIcon}
-            message='Select a file or folder to view its details.' />;
-    }
-}
diff --git a/src/components/details-panel-factory/items/process-item.tsx b/src/components/details-panel-factory/items/process-item.tsx
deleted file mode 100644 (file)
index 1071efc..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright (C) The Arvados Authors. All rights reserved.
-//
-// SPDX-License-Identifier: AGPL-3.0
-
-import * as React from 'react';
-import { ProcessIcon } from '../../icon/icon';
-import { Attribute } from '../../attribute/attribute';
-import { AbstractItem } from './abstract-item';
-import { ProcessResource } from '../../../models/process';
-import { formatDate } from '../../../common/formatters';
-import { ResourceKind } from '../../../models/resource';
-import { resourceLabel } from '../../../common/labels';
-
-export class ProcessItem extends AbstractItem<ProcessResource> {
-
-    getIcon(className?: string){
-        return <ProcessIcon className={className} />;
-    }
-
-    buildDetails() {
-        return <div>
-            <Attribute label='Type' value={resourceLabel(ResourceKind.Process)} />
-            <Attribute label='Size' value='---' />
-            <Attribute label='Owner' value={this.item.ownerUuid} />
-
-            {/* Missing attr */}
-            <Attribute label='Status' value={this.item.state} />
-            <Attribute label='Last modified' value={formatDate(this.item.modifiedAt)} />
-
-            {/* Missing attrs */}
-            <Attribute label='Started at' value={formatDate(this.item.createdAt)} />
-            <Attribute label='Finished at' value={formatDate(this.item.expiresAt)} />
-
-            {/* Links but we dont have view */}
-            <Attribute label='Outputs' link={this.item.outputPath} value={this.item.outputPath} />
-            <Attribute label='UUID' link={this.item.uuid} value={this.item.uuid} />
-            <Attribute label='Container UUID' link={this.item.containerUuid} value={this.item.containerUuid} />
-
-            <Attribute label='Priority' value={this.item.priority} />
-            <Attribute label='Runtime Constraints' value={this.item.runtimeConstraints} />
-            {/* Link but we dont have view */}
-            <Attribute label='Docker Image locator' link={this.item.containerImage} value={this.item.containerImage} />
-        </div>;
-    }
-}
diff --git a/src/components/details-panel-factory/items/project-item.tsx b/src/components/details-panel-factory/items/project-item.tsx
deleted file mode 100644 (file)
index 702aa17..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (C) The Arvados Authors. All rights reserved.
-//
-// SPDX-License-Identifier: AGPL-3.0
-
-import * as React from 'react';
-import { ProjectIcon } from '../../icon/icon';
-import { Attribute } from '../../attribute/attribute';
-import { AbstractItem } from './abstract-item';
-import { ProjectResource } from '../../../models/project';
-import { formatDate } from '../../../common/formatters';
-import { ResourceKind } from '../../../models/resource';
-import { resourceLabel } from '../../../common/labels';
-
-export class ProjectItem extends AbstractItem<ProjectResource> {
-
-    getIcon(className?: string) {
-        return <ProjectIcon className={className} />;
-    }
-
-    buildDetails() {
-        return <div>
-            <Attribute label='Type' value={resourceLabel(ResourceKind.Project)} />
-            {/* Missing attr */}
-            <Attribute label='Size' value='---' />
-            <Attribute label='Owner' value={this.item.ownerUuid} />
-            <Attribute label='Last modified' value={formatDate(this.item.modifiedAt)} />
-            <Attribute label='Created at' value={formatDate(this.item.createdAt)} />
-            {/* Missing attr */}
-            <Attribute label='File size' value='1.4 GB' />
-            <Attribute label='Description' value={this.item.description} />
-        </div>;
-    }
-}
diff --git a/src/components/empty-state/empty-state.tsx b/src/components/empty-state/empty-state.tsx
deleted file mode 100644 (file)
index 75a2aa6..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (C) The Arvados Authors. All rights reserved.
-//
-// SPDX-License-Identifier: AGPL-3.0
-
-import * as React from 'react';
-import Typography from '@material-ui/core/Typography';
-import { WithStyles, withStyles, StyleRulesCallback } from '@material-ui/core/styles';
-import { ArvadosTheme } from 'src/common/custom-theme';
-import { IconType } from '../icon/icon';
-
-type CssRules = 'container' | 'icon';
-const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
-    container: {
-        textAlign: 'center'
-    },
-    icon: {
-        color: theme.palette.grey["500"],
-        fontSize: '72px'
-    }
-});
-
-export interface EmptyStateDataProps {
-    message: string;
-    icon: IconType;
-    details?: string;
-}
-
-type EmptyStateProps = EmptyStateDataProps & WithStyles<CssRules>;
-
-export const EmptyState = withStyles(styles)(
-    class extends React.Component<EmptyStateProps, {}> {
-        render() {
-            const {classes, message, details, icon: Icon, children} = this.props;
-            return (
-                <Typography className={classes.container} component="div">
-                    <Icon className={classes.icon}/>
-                    <Typography variant="body1" gutterBottom>{message}</Typography>
-                    {details && <Typography gutterBottom>{details}</Typography>}
-                    {children && <Typography gutterBottom>{children}</Typography>}
-                </Typography>
-            );
-        }
-    }
-);
index 162e0f57e454879d693dc5882545643503625369..4e5481570e6844100791c8b27b712a9498622963 100644 (file)
@@ -35,5 +35,4 @@ export interface ContainerRequestResource extends Resource {
     logUuid: string;
     outputUuid: string;
     filters: string;
-
-}
\ No newline at end of file
+}
diff --git a/src/models/details.ts b/src/models/details.ts
new file mode 100644 (file)
index 0000000..42eb5c9
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { ProjectResource } from "./project";
+import { CollectionResource } from "./collection";
+import { ProcessResource } from "./process";
+import { EmptyResource } from "./empty";
+
+export type DetailsResource = ProjectResource | CollectionResource | ProcessResource | EmptyResource;
index 9731207f0e725b3d979e046b606b39af8b95c57e..539f9f5719523eba59d5575077985660cb0379db 100644 (file)
@@ -2,9 +2,7 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-import { ResourceKind } from "./resource";
-
 export interface EmptyResource {
     name: string;
     kind: undefined;
-}
\ No newline at end of file
+}
diff --git a/src/views-components/details-panel/collection-details.tsx b/src/views-components/details-panel/collection-details.tsx
new file mode 100644 (file)
index 0000000..2881776
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+import { CollectionIcon } from '../../components/icon/icon';
+import { CollectionResource } from '../../models/collection';
+import { formatDate } from '../../common/formatters';
+import { resourceLabel } from '../../common/labels';
+import { ResourceKind } from '../../models/resource';
+import { DetailsData } from "./details-data";
+import { DetailsAttribute } from "../../components/details-attribute/details-attribute";
+
+export class CollectionDetails extends DetailsData<CollectionResource> {
+
+    getIcon(className?: string) {
+        return <CollectionIcon className={className} />;
+    }
+
+    getDetails() {
+        return <div>
+            <DetailsAttribute label='Type' value={resourceLabel(ResourceKind.Collection)} />
+            <DetailsAttribute label='Size' value='---' />
+            <DetailsAttribute label='Owner' value={this.item.ownerUuid} />
+            <DetailsAttribute label='Last modified' value={formatDate(this.item.modifiedAt)} />
+            <DetailsAttribute label='Created at' value={formatDate(this.item.createdAt)} />
+            {/* Links but we dont have view */}
+            <DetailsAttribute label='Collection UUID' link={this.item.uuid} value={this.item.uuid} />
+            <DetailsAttribute label='Content address' link={this.item.portableDataHash} value={this.item.portableDataHash} />
+            {/* Missing attrs */}
+            <DetailsAttribute label='Number of files' value='20' />
+            <DetailsAttribute label='Content size' value='54 MB' />
+        </div>;
+    }
+}
similarity index 53%
rename from src/components/details-panel-factory/items/abstract-item.tsx
rename to src/views-components/details-panel/details-data.tsx
index 5455d5c5975915f6c00651087684a05983b1a182..d20269cd77ca3e949a286a92fccd477b4be3a9b1 100644 (file)
@@ -3,9 +3,9 @@
 // SPDX-License-Identifier: AGPL-3.0
 
 import * as React from 'react';
-import { DetailsPanelResource } from '../../../views-components/details-panel/details-panel';
+import { DetailsResource } from "../../models/details";
 
-export abstract class AbstractItem<T extends DetailsPanelResource = DetailsPanelResource> {
+export abstract class DetailsData<T extends DetailsResource = DetailsResource> {
     constructor(protected item: T) {}
 
     getTitle(): string {
@@ -13,9 +13,9 @@ export abstract class AbstractItem<T extends DetailsPanelResource = DetailsPanel
     }
 
     abstract getIcon(className?: string): React.ReactElement<any>;
-    abstract buildDetails(): React.ReactElement<any>;
+    abstract getDetails(): React.ReactElement<any>;
 
-    buildActivity(): React.ReactElement<any> {
+    getActivity(): React.ReactElement<any> {
         return <div/>;
     }
 }
index b61a1e41ac8c1f99deda0ff196e02da148d1f17e..ea8f2e40f6288fc27e56275dad668180bbda9484 100644 (file)
@@ -10,14 +10,16 @@ import * as classnames from "classnames";
 import { connect } from 'react-redux';
 import { RootState } from '../../store/store';
 import { detailsPanelActions } from "../../store/details-panel/details-panel-action";
-import { ProjectResource } from '../../models/project';
-import { CollectionResource } from '../../models/collection';
 import { CloseIcon } from '../../components/icon/icon';
-import { ProcessResource } from '../../models/process';
-import { DetailsPanelFactory } from '../../components/details-panel-factory/details-panel-factory';
-import { AbstractItem } from '../../components/details-panel-factory/items/abstract-item';
 import { EmptyResource } from '../../models/empty';
 import { Dispatch } from "redux";
+import { ResourceKind } from "../../models/resource";
+import { ProjectDetails } from "./project-details";
+import { CollectionDetails } from "./collection-details";
+import { ProcessDetails } from "./process-details";
+import { EmptyDetails } from "./empty-details";
+import { DetailsData } from "./details-data";
+import { DetailsResource } from "../../models/details";
 
 type CssRules = 'drawerPaper' | 'container' | 'opened' | 'headerContainer' | 'headerIcon' | 'tabContainer';
 
@@ -50,24 +52,24 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
     }
 });
 
-
-export type DetailsPanelResource = ProjectResource | CollectionResource | ProcessResource | EmptyResource;
-
-const getItem = (res: DetailsPanelResource) => {
-    return DetailsPanelFactory.createItem(res);
-};
-
-const getDefaultItem = () => {
-    return DetailsPanelFactory.createItem({ kind: undefined, name: 'Projects' });
+const getItem = (resource: DetailsResource): DetailsData => {
+    const res = resource || { kind: undefined, name: 'Projects' };
+    switch (res.kind) {
+        case ResourceKind.Project:
+            return new ProjectDetails(res);
+        case ResourceKind.Collection:
+            return new CollectionDetails(res);
+        case ResourceKind.Process:
+            return new ProcessDetails(res);
+        default:
+            return new EmptyDetails(res as EmptyResource);
+    }
 };
 
-const mapStateToProps = ({ detailsPanel }: RootState) => {
-    const { isOpened, item } = detailsPanel;
-    return {
-        isOpened,
-        item: item ? getItem(item as DetailsPanelResource) : getDefaultItem()
-    };
-};
+const mapStateToProps = ({ detailsPanel }: RootState) => ({
+    isOpened: detailsPanel.isOpened,
+    item: getItem(detailsPanel.item as DetailsResource)
+});
 
 const mapDispatchToProps = (dispatch: Dispatch) => ({
     onCloseDrawer: () => {
@@ -78,14 +80,14 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({
 export interface DetailsPanelDataProps {
     onCloseDrawer: () => void;
     isOpened: boolean;
-    item: AbstractItem;
+    item: DetailsData;
 }
 
 type DetailsPanelProps = DetailsPanelDataProps & WithStyles<CssRules>;
 
 export const DetailsPanel = withStyles(styles)(
     connect(mapStateToProps, mapDispatchToProps)(
-        class extends React.Component<DetailsPanelProps, {}> {
+        class extends React.Component<DetailsPanelProps> {
             state = {
                 tabsValue: 0
             };
@@ -129,7 +131,7 @@ export const DetailsPanel = withStyles(styles)(
                             </Tabs>
                             {tabsValue === 0 && this.renderTabContainer(
                                 <Grid container direction="column">
-                                    {item.buildDetails()}
+                                    {item.getDetails()}
                                 </Grid>
                             )}
                             {tabsValue === 1 && this.renderTabContainer(
diff --git a/src/views-components/details-panel/empty-details.tsx b/src/views-components/details-panel/empty-details.tsx
new file mode 100644 (file)
index 0000000..f1ef274
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+import { DefaultIcon, IconType, ProjectsIcon } from '../../components/icon/icon';
+import { EmptyResource } from '../../models/empty';
+import { DetailsData } from "./details-data";
+import Typography from "@material-ui/core/Typography";
+import { StyleRulesCallback, WithStyles, withStyles } from "@material-ui/core/styles";
+import { ArvadosTheme } from "../../common/custom-theme";
+import Icon from "@material-ui/core/Icon/Icon";
+
+type CssRules = 'container' | 'icon';
+
+const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
+    container: {
+        textAlign: 'center'
+    },
+    icon: {
+        color: theme.palette.grey["500"],
+        fontSize: '72px'
+    }
+});
+
+export interface EmptyStateDataProps {
+    message: string;
+    icon: IconType;
+    details?: string;
+    children?: React.ReactNode;
+}
+
+type EmptyStateProps = EmptyStateDataProps & WithStyles<CssRules>;
+
+const EmptyState = withStyles(styles)(
+    ({ classes, details, message, children }: EmptyStateProps) =>
+        <Typography className={classes.container} component="div">
+            <Icon className={classes.icon}/>
+            <Typography variant="body1" gutterBottom>{message}</Typography>
+            {details && <Typography gutterBottom>{details}</Typography>}
+            {children && <Typography gutterBottom>{children}</Typography>}
+        </Typography>
+);
+
+export class EmptyDetails extends DetailsData<EmptyResource> {
+    getIcon(className?: string) {
+        return <ProjectsIcon className={className}/>;
+    }
+
+    getDetails() {
+       return <EmptyState icon={DefaultIcon} message='Select a file or folder to view its details.'/>;
+    }
+}
diff --git a/src/views-components/details-panel/process-details.tsx b/src/views-components/details-panel/process-details.tsx
new file mode 100644 (file)
index 0000000..931ff7e
--- /dev/null
@@ -0,0 +1,45 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+import { ProcessIcon } from '../../components/icon/icon';
+import { ProcessResource } from '../../models/process';
+import { formatDate } from '../../common/formatters';
+import { ResourceKind } from '../../models/resource';
+import { resourceLabel } from '../../common/labels';
+import { DetailsData } from "./details-data";
+import { DetailsAttribute } from "../../components/details-attribute/details-attribute";
+
+export class ProcessDetails extends DetailsData<ProcessResource> {
+
+    getIcon(className?: string){
+        return <ProcessIcon className={className} />;
+    }
+
+    getDetails() {
+        return <div>
+            <DetailsAttribute label='Type' value={resourceLabel(ResourceKind.Process)} />
+            <DetailsAttribute label='Size' value='---' />
+            <DetailsAttribute label='Owner' value={this.item.ownerUuid} />
+
+            {/* Missing attr */}
+            <DetailsAttribute label='Status' value={this.item.state} />
+            <DetailsAttribute label='Last modified' value={formatDate(this.item.modifiedAt)} />
+
+            {/* Missing attrs */}
+            <DetailsAttribute label='Started at' value={formatDate(this.item.createdAt)} />
+            <DetailsAttribute label='Finished at' value={formatDate(this.item.expiresAt)} />
+
+            {/* Links but we dont have view */}
+            <DetailsAttribute label='Outputs' link={this.item.outputPath} value={this.item.outputPath} />
+            <DetailsAttribute label='UUID' link={this.item.uuid} value={this.item.uuid} />
+            <DetailsAttribute label='Container UUID' link={this.item.containerUuid} value={this.item.containerUuid} />
+
+            <DetailsAttribute label='Priority' value={this.item.priority} />
+            <DetailsAttribute label='Runtime Constraints' value={this.item.runtimeConstraints} />
+            {/* Link but we dont have view */}
+            <DetailsAttribute label='Docker Image locator' link={this.item.containerImage} value={this.item.containerImage} />
+        </div>;
+    }
+}
diff --git a/src/views-components/details-panel/project-details.tsx b/src/views-components/details-panel/project-details.tsx
new file mode 100644 (file)
index 0000000..84b3706
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+import { ProjectIcon } from '../../components/icon/icon';
+import { ProjectResource } from '../../models/project';
+import { formatDate } from '../../common/formatters';
+import { ResourceKind } from '../../models/resource';
+import { resourceLabel } from '../../common/labels';
+import { DetailsData } from "./details-data";
+import { DetailsAttribute } from "../../components/details-attribute/details-attribute";
+
+export class ProjectDetails extends DetailsData<ProjectResource> {
+
+    getIcon(className?: string) {
+        return <ProjectIcon className={className} />;
+    }
+
+    getDetails() {
+        return <div>
+            <DetailsAttribute label='Type' value={resourceLabel(ResourceKind.Project)} />
+            {/* Missing attr */}
+            <DetailsAttribute label='Size' value='---' />
+            <DetailsAttribute label='Owner' value={this.item.ownerUuid} />
+            <DetailsAttribute label='Last modified' value={formatDate(this.item.modifiedAt)} />
+            <DetailsAttribute label='Created at' value={formatDate(this.item.createdAt)} />
+            {/* Missing attr */}
+            <DetailsAttribute label='File size' value='1.4 GB' />
+            <DetailsAttribute label='Description' value={this.item.description} />
+        </div>;
+    }
+}