Initial Move from Azure DevOps to GitHub

This commit is contained in:
Steve Faulkner
2020-05-25 21:30:55 -05:00
commit 36581fb6d9
986 changed files with 195242 additions and 0 deletions

View File

@@ -0,0 +1,131 @@
/**
* Wrapper around Notebook metadata
*/
import * as React from "react";
import * as ViewModels from "../../../Contracts/ViewModels";
import { NotebookMetadata } from "../../../Contracts/DataModels";
import { initializeIcons } from "office-ui-fabric-react/lib/Icons";
import { Icon, Persona, Text } from "office-ui-fabric-react";
import CSS from "csstype";
import {
siteTextStyles,
subtleIconStyles,
iconStyles,
mainHelpfulTextStyles,
subtleHelpfulTextStyles,
helpfulTextStyles
} from "../../../GalleryViewer/Cards/CardStyleConstants";
initializeIcons();
interface NotebookMetadataComponentProps {
notebookName: string;
container: ViewModels.Explorer;
notebookMetadata: NotebookMetadata;
notebookContent: any;
}
export class NotebookMetadataComponent extends React.Component<NotebookMetadataComponentProps> {
private inlineBlockStyle: CSS.Properties = {
display: "inline-block"
};
private marginTopStyle: CSS.Properties = {
marginTop: "5px"
};
private onDownloadClick: (newNotebookName: string) => void = (newNotebookName: string) => {
this.props.container.importAndOpenFromGallery(
this.props.notebookName,
newNotebookName,
JSON.stringify(this.props.notebookContent)
);
};
public render(): JSX.Element {
const promptForNotebookName = () => {
return new Promise<string>((resolve, reject) => {
var newNotebookName = this.props.notebookName;
this.props.container.showOkCancelTextFieldModalDialog(
"Save notebook as",
undefined,
"Ok",
() => resolve(newNotebookName),
"Cancel",
() => reject(new Error("New notebook name dialog canceled")),
{
label: "New notebook name:",
autoAdjustHeight: true,
multiline: true,
rows: 3,
defaultValue: this.props.notebookName,
onChange: (_, newValue: string) => {
newNotebookName = newValue;
}
}
);
});
};
return (
<div className="notebookViewerMetadataContainer">
<h3 style={this.inlineBlockStyle}>{this.props.notebookName}</h3>
{this.props.notebookMetadata && (
<div style={this.inlineBlockStyle}>
<Icon iconName="Heart" styles={iconStyles} />
<Text variant="medium" styles={mainHelpfulTextStyles}>
{this.props.notebookMetadata.likes} likes
</Text>
</div>
)}
{this.props.container && (
<button
aria-label="downloadButton"
className="downloadButton"
onClick={async () => {
promptForNotebookName().then(this.onDownloadClick);
}}
>
Download Notebook
</button>
)}
{this.props.notebookMetadata && (
<>
<div>
<Persona
style={this.inlineBlockStyle}
text={this.props.notebookMetadata.author}
secondaryText={this.props.notebookMetadata.date}
/>
</div>
<div>
<div style={this.marginTopStyle}>
<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>
</div>
<Text variant="small" styles={siteTextStyles}>
{this.props.notebookMetadata.tags.join(", ")}
</Text>
</div>
<div>
<Text variant="small" styles={helpfulTextStyles}>
<b>Description:</b>
<p>{this.props.notebookMetadata.description}</p>
</Text>
</div>
</>
)}
</div>
);
}
}

View File

@@ -0,0 +1,11 @@
@import "../../../../less/Common/Constants";
.notebookComponentContainer {
height: 100vh;
width: 100vw;
margin: 0px;
overflow-x: hidden;
font-family: @DataExplorerFont;
padding: 20px;
}

View File

@@ -0,0 +1,41 @@
import React from "react";
import * as ReactDOM from "react-dom";
import "bootstrap/dist/css/bootstrap.css";
import { NotebookMetadata } from "../../../Contracts/DataModels";
import { NotebookViewerComponent } from "./NotebookViewerComponent";
import { SessionStorageUtility, StorageKey } from "../../../Shared/StorageUtility";
const getNotebookUrl = (): string => {
const regex: RegExp = new RegExp("[?&]notebookurl=([^&#]*)|&|#|$");
const results: RegExpExecArray | null = regex.exec(window.location.href);
if (!results || !results[1]) {
return "";
}
return decodeURIComponent(results[1]);
};
const onInit = async () => {
var notebookMetadata: NotebookMetadata;
const notebookMetadataString = SessionStorageUtility.getEntryString(StorageKey.NotebookMetadata);
const notebookName = SessionStorageUtility.getEntryString(StorageKey.NotebookName);
if (notebookMetadataString == "null" || notebookMetadataString != null) {
notebookMetadata = (await JSON.parse(notebookMetadataString)) as NotebookMetadata;
SessionStorageUtility.removeEntry(StorageKey.NotebookMetadata);
SessionStorageUtility.removeEntry(StorageKey.NotebookName);
}
const notebookViewerComponent = (
<NotebookViewerComponent
notebookMetadata={notebookMetadata}
notebookName={notebookName}
notebookUrl={getNotebookUrl()}
container={null}
/>
);
ReactDOM.render(notebookViewerComponent, document.getElementById("notebookContent"));
};
// Entry point
window.addEventListener("load", onInit);

View File

@@ -0,0 +1,26 @@
@import "../../../../less/Common/Constants";
.notebookViewerContainer {
padding: @DefaultSpace;
height: 100%;
width: 100%;
overflow-y: scroll;
}
.downloadButton {
background-color: #0078D4;
color: @BaseLight;
cursor: pointer;
padding: 5px;
border: none;
text-align: left;
outline: none;
font-size: @mediumFontSize;
border-radius: 5px;
display: "inline-block";
margin: 10px;
}
.active, .downloadButton:hover {
color: @BaseMedium;
}

View File

@@ -0,0 +1,88 @@
/**
* Wrapper around Notebook Viewer Read only content
*/
import * as React from "react";
import * as ViewModels from "../../../Contracts/ViewModels";
import { NotebookClientV2 } from "../../Notebook/NotebookClientV2";
import { NotebookComponentBootstrapper } from "../../Notebook/NotebookComponent/NotebookComponentBootstrapper";
import { createContentRef } from "@nteract/core";
import NotebookReadOnlyRenderer from "../../Notebook/NotebookRenderer/NotebookReadOnlyRenderer";
import { contents } from "rx-jupyter";
import { NotebookMetadata } from "../../../Contracts/DataModels";
import { NotebookMetadataComponent } from "./NotebookMetadataComponent";
import "./NotebookViewerComponent.less";
export interface NotebookViewerComponentProps {
notebookName: string;
notebookUrl: string;
container: ViewModels.Explorer;
notebookMetadata: NotebookMetadata;
}
interface NotebookViewerComponentState {
element: JSX.Element;
content: any;
}
export class NotebookViewerComponent extends React.Component<
NotebookViewerComponentProps,
NotebookViewerComponentState
> {
private clientManager: NotebookClientV2;
private notebookComponentBootstrapper: NotebookComponentBootstrapper;
constructor(props: NotebookViewerComponentProps) {
super(props);
this.clientManager = new NotebookClientV2({
connectionInfo: { authToken: undefined, notebookServerEndpoint: undefined },
databaseAccountName: undefined,
defaultExperience: "NotebookViewer",
isReadOnly: true,
cellEditorType: "codemirror",
autoSaveInterval: 365 * 24 * 3600 * 1000, // There is no way to turn off auto-save, set to 1 year
contentProvider: contents.JupyterContentProvider // NotebookViewer only knows how to talk to Jupyter contents API
});
this.notebookComponentBootstrapper = new NotebookComponentBootstrapper({
notebookClient: this.clientManager,
contentRef: createContentRef()
});
this.state = { element: undefined, content: undefined };
}
private async getJsonNotebookContent(): Promise<any> {
const response: Response = await fetch(this.props.notebookUrl);
if (response.ok) {
return await response.json();
} else {
return undefined;
}
}
componentDidMount() {
this.getJsonNotebookContent().then((jsonContent: any) => {
this.notebookComponentBootstrapper.setContent("json", jsonContent);
const notebookReadonlyComponent = this.notebookComponentBootstrapper.renderComponent(NotebookReadOnlyRenderer);
this.setState({ element: notebookReadonlyComponent, content: jsonContent });
});
}
public render(): JSX.Element {
return this.state != null ? (
<div className="notebookViewerContainer">
<NotebookMetadataComponent
notebookMetadata={this.props.notebookMetadata}
notebookName={this.props.notebookName}
container={this.props.container}
notebookContent={this.state.content}
/>
{this.state.element}
</div>
) : (
<></>
);
}
}

View 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>Notebook Viewer</title>
</head>
<body>
<div class="notebookComponentContainer" id="notebookContent"></div>
</body>
</html>