mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-20 09:20:16 +00:00
Initial Move from Azure DevOps to GitHub
This commit is contained in:
55
src/GalleryViewer/Cards/CardStyleConstants.tsx
Normal file
55
src/GalleryViewer/Cards/CardStyleConstants.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import { FontWeights } from "@uifabric/styling";
|
||||
import { IIconStyles, ITextStyles } from "office-ui-fabric-react";
|
||||
|
||||
export const siteTextStyles: ITextStyles = {
|
||||
root: {
|
||||
color: "#025F52",
|
||||
fontWeight: FontWeights.semibold
|
||||
}
|
||||
};
|
||||
|
||||
export const descriptionTextStyles: ITextStyles = {
|
||||
root: {
|
||||
color: "#333333",
|
||||
fontWeight: FontWeights.semibold
|
||||
}
|
||||
};
|
||||
|
||||
export const subtleHelpfulTextStyles: ITextStyles = {
|
||||
root: {
|
||||
color: "#ccc",
|
||||
fontWeight: FontWeights.regular
|
||||
}
|
||||
};
|
||||
|
||||
export const iconStyles: IIconStyles = {
|
||||
root: {
|
||||
marginLeft: "10px",
|
||||
color: "#0078D4",
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeights.regular,
|
||||
display: "inline-block"
|
||||
}
|
||||
};
|
||||
|
||||
export const mainHelpfulTextStyles: ITextStyles = {
|
||||
root: {
|
||||
color: "#000",
|
||||
fontWeight: FontWeights.regular
|
||||
}
|
||||
};
|
||||
|
||||
export const subtleIconStyles: IIconStyles = {
|
||||
root: {
|
||||
color: "#ddd",
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeights.regular
|
||||
}
|
||||
};
|
||||
|
||||
export const helpfulTextStyles: ITextStyles = {
|
||||
root: {
|
||||
color: "#333333",
|
||||
fontWeight: FontWeights.regular
|
||||
}
|
||||
};
|
||||
65
src/GalleryViewer/Cards/GalleryCardComponent.tsx
Normal file
65
src/GalleryViewer/Cards/GalleryCardComponent.tsx
Normal file
@@ -0,0 +1,65 @@
|
||||
import * as React from "react";
|
||||
import * as DataModels from "../../Contracts/DataModels";
|
||||
import { Card, ICardTokens, ICardSectionTokens } from "@uifabric/react-cards";
|
||||
import { Icon, Image, Persona, Text } from "office-ui-fabric-react";
|
||||
import {
|
||||
siteTextStyles,
|
||||
descriptionTextStyles,
|
||||
helpfulTextStyles,
|
||||
subtleHelpfulTextStyles,
|
||||
subtleIconStyles
|
||||
} from "./CardStyleConstants";
|
||||
|
||||
interface GalleryCardComponentProps {
|
||||
name: string;
|
||||
url: string;
|
||||
notebookMetadata: DataModels.NotebookMetadata;
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
export class GalleryCardComponent extends React.Component<GalleryCardComponentProps> {
|
||||
private cardTokens: ICardTokens = { childrenMargin: 12 };
|
||||
private attendantsCardSectionTokens: ICardSectionTokens = { childrenGap: 6 };
|
||||
|
||||
public render(): JSX.Element {
|
||||
return this.props.notebookMetadata != null ? (
|
||||
<Card aria-label="Notebook Card" onClick={this.props.onClick} tokens={this.cardTokens}>
|
||||
<Card.Item>
|
||||
<Persona text={this.props.notebookMetadata.author} secondaryText={this.props.notebookMetadata.date} />
|
||||
</Card.Item>
|
||||
<Card.Item fill>
|
||||
<Image src={this.props.notebookMetadata.imageUrl} width="100%" alt="Notebook display image" />
|
||||
</Card.Item>
|
||||
<Card.Section>
|
||||
<Text variant="small" styles={siteTextStyles}>
|
||||
{this.props.notebookMetadata.tags.join(", ")}
|
||||
</Text>
|
||||
<Text styles={descriptionTextStyles}>{this.props.name}</Text>
|
||||
<Text variant="small" styles={helpfulTextStyles}>
|
||||
{this.props.notebookMetadata.description}
|
||||
</Text>
|
||||
</Card.Section>
|
||||
<Card.Section horizontal tokens={this.attendantsCardSectionTokens}>
|
||||
<Icon iconName="RedEye" styles={subtleIconStyles} />
|
||||
<Text variant="small" styles={subtleHelpfulTextStyles}>
|
||||
{this.props.notebookMetadata.views}
|
||||
</Text>
|
||||
<Icon iconName="Download" styles={subtleIconStyles} />
|
||||
<Text variant="small" styles={subtleHelpfulTextStyles}>
|
||||
{this.props.notebookMetadata.downloads}
|
||||
</Text>
|
||||
<Icon iconName="Heart" styles={subtleIconStyles} />
|
||||
<Text variant="small" styles={subtleHelpfulTextStyles}>
|
||||
{this.props.notebookMetadata.likes}
|
||||
</Text>
|
||||
</Card.Section>
|
||||
</Card>
|
||||
) : (
|
||||
<Card aria-label="Notebook Card" onClick={this.props.onClick} tokens={this.cardTokens}>
|
||||
<Card.Section>
|
||||
<Text styles={descriptionTextStyles}>{this.props.name}</Text>
|
||||
</Card.Section>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
}
|
||||
9
src/GalleryViewer/GalleryViewer.less
Normal file
9
src/GalleryViewer/GalleryViewer.less
Normal file
@@ -0,0 +1,9 @@
|
||||
@import "../../less/Common/Constants";
|
||||
|
||||
.galleryContainer {
|
||||
padding: @DefaultSpace;
|
||||
height: 100%;
|
||||
overflow-y: scroll;
|
||||
width: 100%;
|
||||
font-family: @DataExplorerFont;
|
||||
}
|
||||
20
src/GalleryViewer/GalleryViewer.tsx
Normal file
20
src/GalleryViewer/GalleryViewer.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import * as ReactDOM from "react-dom";
|
||||
import "bootstrap/dist/css/bootstrap.css";
|
||||
import "./GalleryViewer.less";
|
||||
import { GalleryViewerComponent } from "./GalleryViewerComponent";
|
||||
import { JunoUtils } from "../Utils/JunoUtils";
|
||||
import { initializeIcons } from "office-ui-fabric-react/lib/Icons";
|
||||
|
||||
const onInit = async () => {
|
||||
initializeIcons();
|
||||
const officialSamplesData = await JunoUtils.getOfficialSampleNotebooks();
|
||||
const galleryViewerComponent = new GalleryViewerComponent({
|
||||
officialSamplesData: officialSamplesData,
|
||||
likedNotebookData: undefined,
|
||||
container: undefined
|
||||
});
|
||||
ReactDOM.render(galleryViewerComponent.render(), document.getElementById("galleryContent"));
|
||||
};
|
||||
|
||||
// Entry point
|
||||
window.addEventListener("load", onInit);
|
||||
207
src/GalleryViewer/GalleryViewerComponent.tsx
Normal file
207
src/GalleryViewer/GalleryViewerComponent.tsx
Normal file
@@ -0,0 +1,207 @@
|
||||
/**
|
||||
* Gallery Viewer
|
||||
*/
|
||||
|
||||
import * as React from "react";
|
||||
import * as DataModels from "../Contracts/DataModels";
|
||||
import * as ViewModels from "../Contracts/ViewModels";
|
||||
import { GalleryCardComponent } from "./Cards/GalleryCardComponent";
|
||||
import { Stack, IStackTokens } from "office-ui-fabric-react";
|
||||
import AppBar from "@material-ui/core/AppBar";
|
||||
import Tabs from "@material-ui/core/Tabs";
|
||||
import Tab from "@material-ui/core/Tab";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import Box from "@material-ui/core/Box";
|
||||
import { JunoUtils } from "../Utils/JunoUtils";
|
||||
import { CosmosClient } from "../Common/CosmosClient";
|
||||
import { config } from "../Config";
|
||||
import path from "path";
|
||||
import { SessionStorageUtility, StorageKey } from "../Shared/StorageUtility";
|
||||
import "./GalleryViewer.less";
|
||||
|
||||
interface GalleryCardsComponentProps {
|
||||
data: DataModels.GitHubInfoJunoResponse[];
|
||||
onClick: (url: string, notebookMetadata: DataModels.NotebookMetadata) => Promise<void>;
|
||||
}
|
||||
|
||||
class GalleryCardsComponent extends React.Component<GalleryCardsComponentProps> {
|
||||
private sectionStackTokens: IStackTokens = { childrenGap: 30 };
|
||||
public render(): JSX.Element {
|
||||
return (
|
||||
<Stack horizontal wrap tokens={this.sectionStackTokens}>
|
||||
{this.props.data.map((githubInfo: DataModels.GitHubInfoJunoResponse, index: any) => {
|
||||
const name = githubInfo.name;
|
||||
const url = githubInfo.downloadUrl;
|
||||
const notebookMetadata = githubInfo.metadata;
|
||||
|
||||
return (
|
||||
name !== ".gitignore" &&
|
||||
url && (
|
||||
<GalleryCardComponent
|
||||
key={url}
|
||||
name={name}
|
||||
url={url}
|
||||
notebookMetadata={notebookMetadata}
|
||||
onClick={() => this.props.onClick(url, notebookMetadata)}
|
||||
/>
|
||||
)
|
||||
);
|
||||
})}
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const TabPanel = (props: any) => (
|
||||
<Typography
|
||||
component="div"
|
||||
role="tabpanel"
|
||||
hidden={props.value !== props.index}
|
||||
id={`full-width-tabpanel-${props.index}`}
|
||||
aria-labelledby={`full-width-tab-${props.index}`}
|
||||
>
|
||||
{props.value === props.index && <Box p={2}>{props.children}</Box>}
|
||||
</Typography>
|
||||
);
|
||||
|
||||
const a11yProps = (index: number) => {
|
||||
return {
|
||||
id: `full-width-tab-${index}`,
|
||||
"aria-controls": `full-width-tabpanel-${index}`
|
||||
};
|
||||
};
|
||||
|
||||
interface FullWidthTabsProps {
|
||||
officialSamplesContent: DataModels.GitHubInfoJunoResponse[];
|
||||
likedNotebooksContent: DataModels.GitHubInfoJunoResponse[];
|
||||
onClick: (url: string, notebookMetadata: DataModels.NotebookMetadata) => Promise<void>;
|
||||
}
|
||||
|
||||
const FullWidthTabs = (props: FullWidthTabsProps) => {
|
||||
const [value, setValue] = React.useState(0);
|
||||
|
||||
const handleChange = ({}, newValue: any) => {
|
||||
setValue(newValue);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<AppBar position="static" color="transparent" style={{ background: "transparent", boxShadow: "none" }}>
|
||||
<Tabs
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
indicatorColor="primary"
|
||||
textColor="primary"
|
||||
aria-label="gallery tabs"
|
||||
>
|
||||
<Tab label="Official Samples" {...a11yProps(0)} />
|
||||
<Tab label="Liked Notebooks" {...a11yProps(1)} />
|
||||
</Tabs>
|
||||
</AppBar>
|
||||
<TabPanel value={value} index={0}>
|
||||
<GalleryCardsComponent data={props.officialSamplesContent} onClick={props.onClick} />
|
||||
</TabPanel>
|
||||
<TabPanel value={value} index={1}>
|
||||
<GalleryCardsComponent data={props.likedNotebooksContent} onClick={props.onClick} />
|
||||
</TabPanel>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export interface GalleryViewerContainerComponentProps {
|
||||
container: ViewModels.Explorer;
|
||||
}
|
||||
|
||||
export interface GalleryViewerContainerComponentState {
|
||||
officialSamplesData: DataModels.GitHubInfoJunoResponse[];
|
||||
likedNotebooksData: DataModels.LikedNotebooksJunoResponse;
|
||||
}
|
||||
|
||||
export class GalleryViewerContainerComponent extends React.Component<
|
||||
GalleryViewerContainerComponentProps,
|
||||
GalleryViewerContainerComponentState
|
||||
> {
|
||||
constructor(props: GalleryViewerContainerComponentProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
officialSamplesData: undefined,
|
||||
likedNotebooksData: undefined
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
JunoUtils.getOfficialSampleNotebooks().then((data1: DataModels.GitHubInfoJunoResponse[]) => {
|
||||
const officialSamplesData = data1;
|
||||
|
||||
JunoUtils.getLikedNotebooks(CosmosClient.authorizationToken()).then(
|
||||
(data2: DataModels.LikedNotebooksJunoResponse) => {
|
||||
const likedNotebooksData = data2;
|
||||
|
||||
this.setState({
|
||||
officialSamplesData: officialSamplesData,
|
||||
likedNotebooksData: likedNotebooksData
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
public render(): JSX.Element {
|
||||
return this.state.officialSamplesData && this.state.likedNotebooksData ? (
|
||||
<GalleryViewerComponent
|
||||
container={this.props.container}
|
||||
officialSamplesData={this.state.officialSamplesData}
|
||||
likedNotebookData={this.state.likedNotebooksData}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export interface GalleryViewerComponentProps {
|
||||
container: ViewModels.Explorer;
|
||||
officialSamplesData: DataModels.GitHubInfoJunoResponse[];
|
||||
likedNotebookData: DataModels.LikedNotebooksJunoResponse;
|
||||
}
|
||||
|
||||
export class GalleryViewerComponent extends React.Component<GalleryViewerComponentProps> {
|
||||
private authorizationToken = CosmosClient.authorizationToken();
|
||||
|
||||
public render(): JSX.Element {
|
||||
return this.props.container ? (
|
||||
<div className="galleryContainer">
|
||||
<FullWidthTabs
|
||||
officialSamplesContent={this.props.officialSamplesData}
|
||||
likedNotebooksContent={this.props.likedNotebookData.likedNotebooksContent}
|
||||
onClick={this.openNotebookViewer}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className="galleryContainer">
|
||||
<GalleryCardsComponent data={this.props.officialSamplesData} onClick={this.openNotebookViewer} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
public getOfficialSamplesData(): DataModels.GitHubInfoJunoResponse[] {
|
||||
return this.props.officialSamplesData;
|
||||
}
|
||||
|
||||
public getLikedNotebookData(): DataModels.LikedNotebooksJunoResponse {
|
||||
return this.props.likedNotebookData;
|
||||
}
|
||||
|
||||
public openNotebookViewer = async (url: string, notebookMetadata: DataModels.NotebookMetadata) => {
|
||||
if (!this.props.container) {
|
||||
SessionStorageUtility.setEntryString(
|
||||
StorageKey.NotebookMetadata,
|
||||
notebookMetadata ? JSON.stringify(notebookMetadata) : null
|
||||
);
|
||||
SessionStorageUtility.setEntryString(StorageKey.NotebookName, path.basename(url));
|
||||
window.open(`${config.hostedExplorerURL}notebookViewer.html?notebookurl=${url}`, "_blank");
|
||||
} else {
|
||||
this.props.container.openNotebookViewer(url, notebookMetadata);
|
||||
}
|
||||
};
|
||||
}
|
||||
13
src/GalleryViewer/galleryViewer.html
Normal file
13
src/GalleryViewer/galleryViewer.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="height=device-height, width=device-width, initial-scale=1.0" />
|
||||
|
||||
<title>Gallery Viewer</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="galleryComponentContainer" id="galleryContent"></div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user