mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-19 17:01:13 +00:00
Notebooks Gallery (#59)
* Initial commit * Address PR comments * Move notebook related stuff to NotebookManager and dynamically load it * Add New gallery callout and other UI tweaks * Update test snapshot
This commit is contained in:
@@ -2,10 +2,10 @@ import ko from "knockout";
|
||||
import { HttpStatusCodes } from "../Common/Constants";
|
||||
import { config } from "../Config";
|
||||
import * as ViewModels from "../Contracts/ViewModels";
|
||||
import { AuthorizeAccessComponent } from "../Explorer/Controls/GitHub/AuthorizeAccessComponent";
|
||||
import { IGitHubResponse } from "../GitHub/GitHubClient";
|
||||
import { IGitHubOAuthToken } from "../GitHub/GitHubOAuthService";
|
||||
import { getAuthorizationHeader } from "../Utils/AuthorizationUtils";
|
||||
import { AuthorizeAccessComponent } from "../Explorer/Controls/GitHub/AuthorizeAccessComponent";
|
||||
|
||||
export interface IJunoResponse<T> {
|
||||
status: number;
|
||||
@@ -23,10 +23,39 @@ export interface IPinnedBranch {
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface IGalleryItem {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
gitSha: string;
|
||||
tags: string[];
|
||||
author: string;
|
||||
thumbnailUrl: string;
|
||||
created: string;
|
||||
isSample: boolean;
|
||||
downloads: number;
|
||||
favorites: number;
|
||||
views: number;
|
||||
}
|
||||
|
||||
export interface IUserGallery {
|
||||
favorites: string[];
|
||||
published: string[];
|
||||
}
|
||||
|
||||
interface IPublishNotebookRequest {
|
||||
name: string;
|
||||
description: string;
|
||||
tags: string[];
|
||||
author: string;
|
||||
thumbnailUrl: string;
|
||||
content: any;
|
||||
}
|
||||
|
||||
export class JunoClient {
|
||||
private cachedPinnedRepos: ko.Observable<IPinnedRepo[]>;
|
||||
|
||||
constructor(public databaseAccount: ko.Observable<ViewModels.DatabaseAccount>) {
|
||||
constructor(private databaseAccount?: ko.Observable<ViewModels.DatabaseAccount>) {
|
||||
this.cachedPinnedRepos = ko.observable<IPinnedRepo[]>([]);
|
||||
}
|
||||
|
||||
@@ -35,8 +64,8 @@ export class JunoClient {
|
||||
}
|
||||
|
||||
public async getPinnedRepos(scope: string): Promise<IJunoResponse<IPinnedRepo[]>> {
|
||||
const response = await window.fetch(`${this.getJunoGitHubUrl()}/pinnedrepos`, {
|
||||
headers: this.getHeaders()
|
||||
const response = await window.fetch(`${this.getNotebooksAccountUrl()}/github/pinnedrepos`, {
|
||||
headers: JunoClient.getHeaders()
|
||||
});
|
||||
|
||||
let pinnedRepos: IPinnedRepo[];
|
||||
@@ -58,10 +87,10 @@ export class JunoClient {
|
||||
}
|
||||
|
||||
public async updatePinnedRepos(repos: IPinnedRepo[]): Promise<IJunoResponse<undefined>> {
|
||||
const response = await window.fetch(`${this.getJunoGitHubUrl()}/pinnedrepos`, {
|
||||
const response = await window.fetch(`${this.getNotebooksAccountUrl()}/github/pinnedrepos`, {
|
||||
method: "PUT",
|
||||
body: JSON.stringify(repos),
|
||||
headers: this.getHeaders()
|
||||
headers: JunoClient.getHeaders()
|
||||
});
|
||||
|
||||
if (response.status === HttpStatusCodes.OK) {
|
||||
@@ -75,9 +104,9 @@ export class JunoClient {
|
||||
}
|
||||
|
||||
public async deleteGitHubInfo(): Promise<IJunoResponse<undefined>> {
|
||||
const response = await window.fetch(this.getJunoGitHubUrl(), {
|
||||
const response = await window.fetch(`${this.getNotebooksAccountUrl()}/github`, {
|
||||
method: "DELETE",
|
||||
headers: this.getHeaders()
|
||||
headers: JunoClient.getHeaders()
|
||||
});
|
||||
|
||||
return {
|
||||
@@ -90,8 +119,8 @@ export class JunoClient {
|
||||
const githubParams = JunoClient.getGitHubClientParams();
|
||||
githubParams.append("code", code);
|
||||
|
||||
const response = await window.fetch(`${this.getJunoGitHubUrl()}/token?${githubParams.toString()}`, {
|
||||
headers: this.getHeaders()
|
||||
const response = await window.fetch(`${this.getNotebooksAccountUrl()}/github/token?${githubParams.toString()}`, {
|
||||
headers: JunoClient.getHeaders()
|
||||
});
|
||||
|
||||
let data: IGitHubOAuthToken;
|
||||
@@ -114,9 +143,9 @@ export class JunoClient {
|
||||
const githubParams = JunoClient.getGitHubClientParams();
|
||||
githubParams.append("access_token", token);
|
||||
|
||||
const response = await window.fetch(`${this.getJunoGitHubUrl()}/token?${githubParams.toString()}`, {
|
||||
const response = await window.fetch(`${this.getNotebooksAccountUrl()}/github/token?${githubParams.toString()}`, {
|
||||
method: "DELETE",
|
||||
headers: this.getHeaders()
|
||||
headers: JunoClient.getHeaders()
|
||||
});
|
||||
|
||||
return {
|
||||
@@ -125,11 +154,201 @@ export class JunoClient {
|
||||
};
|
||||
}
|
||||
|
||||
private getJunoGitHubUrl(): string {
|
||||
return `${config.JUNO_ENDPOINT}/api/notebooks/${this.databaseAccount().name}/github`;
|
||||
public async getSampleNotebooks(): Promise<IJunoResponse<IGalleryItem[]>> {
|
||||
return this.getNotebooks(`${this.getNotebooksUrl()}/gallery/samples`);
|
||||
}
|
||||
|
||||
private getHeaders(): HeadersInit {
|
||||
public async getPublicNotebooks(): Promise<IJunoResponse<IGalleryItem[]>> {
|
||||
return this.getNotebooks(`${this.getNotebooksUrl()}/gallery/public`);
|
||||
}
|
||||
|
||||
public async getNotebook(id: string): Promise<IJunoResponse<IGalleryItem>> {
|
||||
const response = await window.fetch(this.getNotebookInfoUrl(id));
|
||||
|
||||
let data: IGalleryItem;
|
||||
if (response.status === HttpStatusCodes.OK) {
|
||||
data = await response.json();
|
||||
}
|
||||
|
||||
return {
|
||||
status: response.status,
|
||||
data
|
||||
};
|
||||
}
|
||||
|
||||
public async getNotebookContent(id: string): Promise<IJunoResponse<string>> {
|
||||
const response = await window.fetch(this.getNotebookContentUrl(id));
|
||||
|
||||
let data: string;
|
||||
if (response.status === HttpStatusCodes.OK) {
|
||||
data = await response.text();
|
||||
}
|
||||
|
||||
return {
|
||||
status: response.status,
|
||||
data
|
||||
};
|
||||
}
|
||||
|
||||
public async increaseNotebookViews(id: string): Promise<IJunoResponse<IGalleryItem>> {
|
||||
const response = await window.fetch(`${this.getNotebooksUrl()}/gallery/${id}/views`, {
|
||||
method: "PATCH"
|
||||
});
|
||||
|
||||
let data: IGalleryItem;
|
||||
if (response.status === HttpStatusCodes.OK) {
|
||||
data = await response.json();
|
||||
}
|
||||
|
||||
return {
|
||||
status: response.status,
|
||||
data
|
||||
};
|
||||
}
|
||||
|
||||
public async increaseNotebookDownloadCount(id: string): Promise<IJunoResponse<IGalleryItem>> {
|
||||
const response = await window.fetch(`${this.getNotebooksAccountUrl()}/gallery/${id}/downloads`, {
|
||||
method: "PATCH",
|
||||
headers: JunoClient.getHeaders()
|
||||
});
|
||||
|
||||
let data: IGalleryItem;
|
||||
if (response.status === HttpStatusCodes.OK) {
|
||||
data = await response.json();
|
||||
}
|
||||
|
||||
return {
|
||||
status: response.status,
|
||||
data
|
||||
};
|
||||
}
|
||||
|
||||
public async favoriteNotebook(id: string): Promise<IJunoResponse<IGalleryItem>> {
|
||||
const response = await window.fetch(`${this.getNotebooksAccountUrl()}/gallery/${id}/favorite`, {
|
||||
method: "PATCH",
|
||||
headers: JunoClient.getHeaders()
|
||||
});
|
||||
|
||||
let data: IGalleryItem;
|
||||
if (response.status === HttpStatusCodes.OK) {
|
||||
data = await response.json();
|
||||
}
|
||||
|
||||
return {
|
||||
status: response.status,
|
||||
data
|
||||
};
|
||||
}
|
||||
|
||||
public async unfavoriteNotebook(id: string): Promise<IJunoResponse<IGalleryItem>> {
|
||||
const response = await window.fetch(`${this.getNotebooksUrl()}/gallery/${id}/unfavorite`, {
|
||||
method: "PATCH",
|
||||
headers: JunoClient.getHeaders()
|
||||
});
|
||||
|
||||
let data: IGalleryItem;
|
||||
if (response.status === HttpStatusCodes.OK) {
|
||||
data = await response.json();
|
||||
}
|
||||
|
||||
return {
|
||||
status: response.status,
|
||||
data
|
||||
};
|
||||
}
|
||||
|
||||
public async getFavoriteNotebooks(): Promise<IJunoResponse<IGalleryItem[]>> {
|
||||
return await this.getNotebooks(`${this.getNotebooksUrl()}/gallery/favorites`, {
|
||||
headers: JunoClient.getHeaders()
|
||||
});
|
||||
}
|
||||
|
||||
public async getPublishedNotebooks(): Promise<IJunoResponse<IGalleryItem[]>> {
|
||||
return await this.getNotebooks(`${this.getNotebooksUrl()}/gallery/published`, {
|
||||
headers: JunoClient.getHeaders()
|
||||
});
|
||||
}
|
||||
|
||||
public async deleteNotebook(id: string): Promise<IJunoResponse<IGalleryItem>> {
|
||||
const response = await window.fetch(`${this.getNotebooksUrl()}/gallery/${id}`, {
|
||||
method: "DELETE",
|
||||
headers: JunoClient.getHeaders()
|
||||
});
|
||||
|
||||
let data: IGalleryItem;
|
||||
if (response.status === HttpStatusCodes.OK) {
|
||||
data = await response.json();
|
||||
}
|
||||
|
||||
return {
|
||||
status: response.status,
|
||||
data
|
||||
};
|
||||
}
|
||||
|
||||
public async publishNotebook(
|
||||
name: string,
|
||||
description: string,
|
||||
tags: string[],
|
||||
author: string,
|
||||
thumbnailUrl: string,
|
||||
content: string
|
||||
): Promise<IJunoResponse<IGalleryItem>> {
|
||||
const response = await window.fetch(`${this.getNotebooksAccountUrl()}/gallery`, {
|
||||
method: "PUT",
|
||||
headers: JunoClient.getHeaders(),
|
||||
body: JSON.stringify({
|
||||
name,
|
||||
description,
|
||||
tags,
|
||||
author,
|
||||
thumbnailUrl,
|
||||
content: JSON.parse(content)
|
||||
} as IPublishNotebookRequest)
|
||||
});
|
||||
|
||||
let data: IGalleryItem;
|
||||
if (response.status === HttpStatusCodes.OK) {
|
||||
data = await response.json();
|
||||
}
|
||||
|
||||
return {
|
||||
status: response.status,
|
||||
data
|
||||
};
|
||||
}
|
||||
|
||||
public getNotebookContentUrl(id: string): string {
|
||||
return `${this.getNotebooksUrl()}/gallery/${id}/content`;
|
||||
}
|
||||
|
||||
public getNotebookInfoUrl(id: string): string {
|
||||
return `${this.getNotebooksUrl()}/gallery/${id}`;
|
||||
}
|
||||
|
||||
private async getNotebooks(input: RequestInfo, init?: RequestInit): Promise<IJunoResponse<IGalleryItem[]>> {
|
||||
const response = await window.fetch(input, init);
|
||||
|
||||
let data: IGalleryItem[];
|
||||
if (response.status === HttpStatusCodes.OK) {
|
||||
data = await response.json();
|
||||
}
|
||||
|
||||
return {
|
||||
status: response.status,
|
||||
data
|
||||
};
|
||||
}
|
||||
|
||||
private getNotebooksUrl(): string {
|
||||
return `${config.JUNO_ENDPOINT}/api/notebooks`;
|
||||
}
|
||||
|
||||
private getNotebooksAccountUrl(): string {
|
||||
return `${config.JUNO_ENDPOINT}/api/notebooks/${this.databaseAccount().name}`;
|
||||
}
|
||||
|
||||
private static getHeaders(): HeadersInit {
|
||||
const authorizationHeader = getAuthorizationHeader();
|
||||
return {
|
||||
[authorizationHeader.header]: authorizationHeader.token,
|
||||
@@ -137,7 +356,7 @@ export class JunoClient {
|
||||
};
|
||||
}
|
||||
|
||||
public static getGitHubClientParams(): URLSearchParams {
|
||||
private static getGitHubClientParams(): URLSearchParams {
|
||||
const githubParams = new URLSearchParams({
|
||||
client_id: config.GITHUB_CLIENT_ID
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user