Remove enableGallery feature flag (#68)

* Remove enableGallery feature flag

* Fix bugs

* Add tests to increase coverage

* Move favorites functionality behind feature.enableGalleryPublish flag

* Show code cells in NotebookViewer

* Use cosmos db logo as persona image for sample notebook gallery cards

* Update gallery card snapshot to fix test
This commit is contained in:
Tanuj Mittal
2020-07-06 12:10:26 -07:00
committed by GitHub
parent 27024ef75c
commit 84ea3796ec
29 changed files with 594 additions and 445 deletions

View File

@@ -0,0 +1,116 @@
import * as GalleryUtils from "./GalleryUtils";
import { JunoClient, IGalleryItem } from "../Juno/JunoClient";
import { ExplorerStub } from "../Explorer/OpenActionsStubs";
import { HttpStatusCodes } from "../Common/Constants";
import { GalleryTab, SortBy } from "../Explorer/Controls/NotebookGallery/GalleryViewerComponent";
const galleryItem: IGalleryItem = {
id: "id",
name: "name",
description: "description",
gitSha: "gitSha",
tags: ["tag1"],
author: "author",
thumbnailUrl: "thumbnailUrl",
created: "created",
isSample: false,
downloads: 0,
favorites: 0,
views: 0
};
describe("GalleryUtils", () => {
afterEach(() => {
jest.resetAllMocks();
});
it("downloadItem shows dialog in standalone gallery", () => {
const setDialogProps = jest.fn().mockImplementation();
GalleryUtils.downloadItem({ setDialogProps }, undefined, undefined, galleryItem, undefined);
expect(setDialogProps).toBeCalled();
});
it("downloadItem shows dialog in data explorer", () => {
const setDialogProps = jest.fn().mockImplementation();
const container = new ExplorerStub();
container.showOkCancelModalDialog = jest.fn().mockImplementation();
GalleryUtils.downloadItem({ setDialogProps }, container, undefined, galleryItem, undefined);
expect(setDialogProps).not.toBeCalled();
expect(container.showOkCancelModalDialog).toBeCalled();
});
it("favoriteItem favorites item", async () => {
const container = new ExplorerStub();
const junoClient = new JunoClient();
junoClient.favoriteNotebook = jest
.fn()
.mockReturnValue(Promise.resolve({ status: HttpStatusCodes.OK, data: galleryItem }));
const onComplete = jest.fn().mockImplementation();
await GalleryUtils.favoriteItem(container, junoClient, galleryItem, onComplete);
expect(junoClient.favoriteNotebook).toBeCalledWith(galleryItem.id);
expect(onComplete).toBeCalledWith(galleryItem);
});
it("unfavoriteItem unfavorites item", async () => {
const container = new ExplorerStub();
const junoClient = new JunoClient();
junoClient.unfavoriteNotebook = jest
.fn()
.mockReturnValue(Promise.resolve({ status: HttpStatusCodes.OK, data: galleryItem }));
const onComplete = jest.fn().mockImplementation();
await GalleryUtils.unfavoriteItem(container, junoClient, galleryItem, onComplete);
expect(junoClient.unfavoriteNotebook).toBeCalledWith(galleryItem.id);
expect(onComplete).toBeCalledWith(galleryItem);
});
it("deleteItem shows dialog in data explorer", () => {
const container = new ExplorerStub();
container.showOkCancelModalDialog = jest.fn().mockImplementation();
GalleryUtils.deleteItem(container, undefined, galleryItem, undefined);
expect(container.showOkCancelModalDialog).toBeCalled();
});
it("getGalleryViewerProps gets gallery viewer props correctly", () => {
const selectedTab: GalleryTab = GalleryTab.OfficialSamples;
const sortBy: SortBy = SortBy.MostDownloaded;
const searchText = "my-complicated%20search%20query!!!";
const response = GalleryUtils.getGalleryViewerProps(
`?${GalleryUtils.GalleryViewerParams.SelectedTab}=${GalleryTab[selectedTab]}&${GalleryUtils.GalleryViewerParams.SortBy}=${SortBy[sortBy]}&${GalleryUtils.GalleryViewerParams.SearchText}=${searchText}`
);
expect(response).toEqual({
selectedTab,
sortBy,
searchText: decodeURIComponent(searchText)
});
});
it("getNotebookViewerProps gets notebook viewer props correctly", () => {
const notebookUrl = "https%3A%2F%2Fnotebook.url";
const galleryItemId = "1234-abcd-efgh";
const response = GalleryUtils.getNotebookViewerProps(
`?${GalleryUtils.NotebookViewerParams.NotebookUrl}=${notebookUrl}&${GalleryUtils.NotebookViewerParams.GalleryItemId}=${galleryItemId}`
);
expect(response).toEqual({
notebookUrl: decodeURIComponent(notebookUrl),
galleryItemId
});
});
it("getTabTitle returns correct title for official samples", () => {
expect(GalleryUtils.getTabTitle(GalleryTab.OfficialSamples)).toBe("Official samples");
});
});

View File

@@ -36,7 +36,7 @@ export interface GalleryViewerProps {
searchText: string;
}
export function showOkCancelModalDialog(
function showOkCancelModalDialog(
component: DialogEnabledComponent,
title: string,
msg: string,
@@ -91,7 +91,7 @@ export function downloadItem(
throw new Error(`Received HTTP ${response.status} when fetching ${data.name}`);
}
await container.importAndOpenFromGallery(data.name, response.data);
await container.importAndOpenContent(data.name, response.data);
NotificationConsoleUtils.logConsoleMessage(
ConsoleDataType.Info,
`Successfully downloaded ${name} to My Notebooks`
@@ -217,8 +217,8 @@ export function deleteItem(
}
}
export function getGalleryViewerProps(window: Window & typeof globalThis): GalleryViewerProps {
const params = new URLSearchParams(window.location.search);
export function getGalleryViewerProps(search: string): GalleryViewerProps {
const params = new URLSearchParams(search);
let selectedTab: GalleryTab;
if (params.has(GalleryViewerParams.SelectedTab)) {
selectedTab = GalleryTab[params.get(GalleryViewerParams.SelectedTab) as keyof typeof GalleryTab];
@@ -236,8 +236,8 @@ export function getGalleryViewerProps(window: Window & typeof globalThis): Galle
};
}
export function getNotebookViewerProps(window: Window & typeof globalThis): NotebookViewerProps {
const params = new URLSearchParams(window.location.search);
export function getNotebookViewerProps(search: string): NotebookViewerProps {
const params = new URLSearchParams(search);
return {
notebookUrl: params.get(NotebookViewerParams.NotebookUrl),
galleryItemId: params.get(NotebookViewerParams.GalleryItemId)

View File

@@ -58,3 +58,7 @@ export function fromContentUri(
export function toContentUri(owner: string, repo: string, branch: string, path: string): string {
return `github://${owner}/${repo}/${path}?ref=${branch}`;
}
export function toRawContentUri(owner: string, repo: string, branch: string, path: string): string {
return `https://raw.githubusercontent.com/${owner}/${repo}/${branch}/${path}`;
}

View File

@@ -0,0 +1,45 @@
import { RepoListItem } from "../Explorer/Controls/GitHub/GitHubReposComponent";
import { IPinnedRepo } from "../Juno/JunoClient";
import { JunoUtils } from "./JunoUtils";
import { IGitHubRepo } from "../GitHub/GitHubClient";
const gitHubRepo: IGitHubRepo = {
name: "repo-name",
owner: "owner",
private: false
};
const repoListItem: RepoListItem = {
key: "key",
repo: {
name: "repo-name",
owner: "owner",
private: false
},
branches: [
{
name: "branch-name"
}
]
};
const pinnedRepo: IPinnedRepo = {
name: "repo-name",
owner: "owner",
private: false,
branches: [
{
name: "branch-name"
}
]
};
describe("JunoUtils", () => {
it("toPinnedRepo converts RepoListItem to IPinnedRepo", () => {
expect(JunoUtils.toPinnedRepo(repoListItem)).toEqual(pinnedRepo);
});
it("toGitHubRepo converts IPinnedRepo to IGitHubRepo", () => {
expect(JunoUtils.toGitHubRepo(pinnedRepo)).toEqual(gitHubRepo);
});
});

View File

@@ -0,0 +1,24 @@
import AuthHeadersUtil from "../Platform/Hosted/Authorization";
import * as UserUtils from "./UserUtils";
describe("UserUtils", () => {
it("getFullName works in regular data explorer (inside portal)", () => {
const user: AuthenticationContext.UserInfo = {
userName: "userName",
profile: {
name: "name"
}
};
AuthHeadersUtil.getCachedUser = jest.fn().mockReturnValue(user);
expect(UserUtils.getFullName()).toBe("name");
});
it("getFullName works in fullscreen data explorer (outside portal)", () => {
jest.mock("./AuthorizationUtils", () => {
(): { name: string } => ({ name: "name" });
});
expect(UserUtils.getFullName()).toBe("name");
});
});