Remove gallery.html and all associated gallery functionality (#2474)

* Remove gallery.html and all associated gallery functionality

Remove the standalone gallery.html entry point, the in-app gallery tab,
the publish-to-gallery pane, and all gallery-related components, utilities,
and API methods that are no longer needed.

Deleted:
- src/GalleryViewer/ (standalone entry point)
- src/Explorer/Controls/NotebookGallery/ (gallery components)
- src/Explorer/Controls/Header/GalleryHeaderComponent.tsx
- src/Explorer/Tabs/GalleryTab.tsx
- src/Explorer/Panes/PublishNotebookPane/ (publish pane)
- src/Utils/GalleryUtils.ts and tests
- images/GalleryIcon.svg

Edited:
- webpack.config.js (removed entry point and HTML plugin)
- Explorer.tsx (removed openGallery, publishNotebook methods)
- ResourceTreeAdapter.tsx (removed gallery tree node and publish menu)
- NotebookV2Tab.ts (removed publish-to-gallery button)
- NotebookManager.tsx (removed openPublishNotebookPane)
- NotebookViewerComponent.tsx (stripped gallery actions)
- JunoClient.ts (removed gallery interfaces and API methods)
- TelemetryConstants.ts, Constants.ts, ViewModels.ts,
  extractFeatures.ts, useKnockoutExplorer.ts (removed gallery constants)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Update package-lock

* Revert changes to Telemetry Constants

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
jawelton74
2026-05-22 09:30:34 -07:00
committed by GitHub
parent 7a9a3aee2d
commit 7295d63aaf
44 changed files with 22 additions and 4229 deletions
+2 -297
View File
@@ -1,24 +1,5 @@
import { HttpHeaders, HttpStatusCodes } from "../Common/Constants";
import { DatabaseAccount } from "../Contracts/DataModels";
import { updateUserContext, userContext } from "../UserContext";
import { getAuthorizationHeader } from "../Utils/AuthorizationUtils";
import { IPinnedRepo, IPublishNotebookRequest, JunoClient } from "./JunoClient";
const sampleSubscriptionId = "subscriptionId";
const sampleDatabaseAccount: DatabaseAccount = {
id: "id",
name: "name",
location: "location",
type: "type",
kind: "kind",
properties: {
documentEndpoint: "documentEndpoint",
gremlinEndpoint: "gremlinEndpoint",
tableEndpoint: "tableEndpoint",
cassandraEndpoint: "cassandraEndpoint",
},
};
import { HttpStatusCodes } from "../Common/Constants";
import { IPinnedRepo, JunoClient } from "./JunoClient";
const samplePinnedRepos: IPinnedRepo[] = [
{
@@ -130,279 +111,3 @@ describe("GitHub", () => {
expect(fetchUrlParams.get("client_id")).toBeDefined();
});
});
describe("Gallery", () => {
const junoClient = new JunoClient();
const originalSubscriptionId = userContext.subscriptionId;
beforeAll(() => {
updateUserContext({
databaseAccount: {
name: "name",
} as DatabaseAccount,
subscriptionId: sampleSubscriptionId,
});
});
afterEach(() => {
jest.resetAllMocks();
});
afterAll(() => {
updateUserContext({ subscriptionId: originalSubscriptionId });
});
it("getSampleNotebooks", async () => {
window.fetch = jest.fn().mockReturnValue({
status: HttpStatusCodes.OK,
json: () => undefined as undefined,
});
const response = await junoClient.getSampleNotebooks();
expect(response.status).toBe(HttpStatusCodes.OK);
expect(window.fetch).toHaveBeenCalledWith(
`${JunoClient.getJunoEndpoint()}/api/notebooks/gallery/samples`,
undefined,
);
});
it("getPublicNotebooks", async () => {
window.fetch = jest.fn().mockReturnValue({
status: HttpStatusCodes.OK,
json: () => undefined as undefined,
});
const response = await junoClient.getPublicNotebooks();
expect(response.status).toBe(HttpStatusCodes.OK);
expect(window.fetch).toHaveBeenCalledWith(
`${JunoClient.getJunoEndpoint()}/api/notebooks/gallery/public`,
undefined,
);
});
it("getNotebook", async () => {
const id = "id";
window.fetch = jest.fn().mockReturnValue({
status: HttpStatusCodes.OK,
json: () => undefined as undefined,
});
const response = await junoClient.getNotebookInfo(id);
expect(response.status).toBe(HttpStatusCodes.OK);
expect(window.fetch).toHaveBeenCalledWith(`${JunoClient.getJunoEndpoint()}/api/notebooks/gallery/${id}`);
});
it("getNotebookContent", async () => {
const id = "id";
window.fetch = jest.fn().mockReturnValue({
status: HttpStatusCodes.OK,
text: () => undefined as undefined,
});
const response = await junoClient.getNotebookContent(id);
expect(response.status).toBe(HttpStatusCodes.OK);
expect(window.fetch).toHaveBeenCalledWith(`${JunoClient.getJunoEndpoint()}/api/notebooks/gallery/${id}/content`);
});
it("increaseNotebookViews", async () => {
const id = "id";
window.fetch = jest.fn().mockReturnValue({
status: HttpStatusCodes.OK,
json: () => undefined as undefined,
});
const response = await junoClient.increaseNotebookViews(id);
expect(response.status).toBe(HttpStatusCodes.OK);
expect(window.fetch).toHaveBeenCalledWith(`${JunoClient.getJunoEndpoint()}/api/notebooks/gallery/${id}/views`, {
method: "PATCH",
});
});
it("increaseNotebookDownloadCount", async () => {
const id = "id";
window.fetch = jest.fn().mockReturnValue({
status: HttpStatusCodes.OK,
json: () => undefined as undefined,
});
const response = await junoClient.increaseNotebookDownloadCount(id);
const authorizationHeader = getAuthorizationHeader();
expect(response.status).toBe(HttpStatusCodes.OK);
expect(window.fetch).toHaveBeenCalledWith(
`${JunoClient.getJunoEndpoint()}/api/notebooks/subscriptions/${sampleSubscriptionId}/databaseAccounts/${
sampleDatabaseAccount.name
}/gallery/${id}/downloads`,
{
method: "PATCH",
headers: {
[authorizationHeader.header]: authorizationHeader.token,
[HttpHeaders.contentType]: "application/json",
},
},
);
});
it("favoriteNotebook", async () => {
const id = "id";
window.fetch = jest.fn().mockReturnValue({
status: HttpStatusCodes.OK,
json: () => undefined as undefined,
});
const response = await junoClient.favoriteNotebook(id);
const authorizationHeader = getAuthorizationHeader();
expect(response.status).toBe(HttpStatusCodes.OK);
expect(window.fetch).toHaveBeenCalledWith(
`${JunoClient.getJunoEndpoint()}/api/notebooks/subscriptions/${sampleSubscriptionId}/databaseAccounts/${
sampleDatabaseAccount.name
}/gallery/${id}/favorite`,
{
method: "PATCH",
headers: {
[authorizationHeader.header]: authorizationHeader.token,
[HttpHeaders.contentType]: "application/json",
},
},
);
});
it("unfavoriteNotebook", async () => {
const id = "id";
window.fetch = jest.fn().mockReturnValue({
status: HttpStatusCodes.OK,
json: () => undefined as undefined,
});
const response = await junoClient.unfavoriteNotebook(id);
const authorizationHeader = getAuthorizationHeader();
expect(response.status).toBe(HttpStatusCodes.OK);
expect(window.fetch).toHaveBeenCalledWith(
`${JunoClient.getJunoEndpoint()}/api/notebooks/subscriptions/${sampleSubscriptionId}/databaseAccounts/${
sampleDatabaseAccount.name
}/gallery/${id}/unfavorite`,
{
method: "PATCH",
headers: {
[authorizationHeader.header]: authorizationHeader.token,
[HttpHeaders.contentType]: "application/json",
},
},
);
});
it("getFavoriteNotebooks", async () => {
window.fetch = jest.fn().mockReturnValue({
status: HttpStatusCodes.OK,
json: () => undefined as undefined,
});
const response = await junoClient.getFavoriteNotebooks();
const authorizationHeader = getAuthorizationHeader();
expect(response.status).toBe(HttpStatusCodes.OK);
expect(window.fetch).toHaveBeenCalledWith(
`${JunoClient.getJunoEndpoint()}/api/notebooks/subscriptions/${sampleSubscriptionId}/databaseAccounts/${
sampleDatabaseAccount.name
}/gallery/favorites`,
{
headers: {
[authorizationHeader.header]: authorizationHeader.token,
[HttpHeaders.contentType]: "application/json",
},
},
);
});
it("getPublishedNotebooks", async () => {
window.fetch = jest.fn().mockReturnValue({
status: HttpStatusCodes.OK,
json: () => undefined as undefined,
});
const response = await junoClient.getPublishedNotebooks();
const authorizationHeader = getAuthorizationHeader();
expect(response.status).toBe(HttpStatusCodes.OK);
expect(window.fetch).toHaveBeenCalledWith(
`${JunoClient.getJunoEndpoint()}/api/notebooks/subscriptions/${sampleSubscriptionId}/databaseAccounts/${
sampleDatabaseAccount.name
}/gallery/published`,
{
headers: {
[authorizationHeader.header]: authorizationHeader.token,
[HttpHeaders.contentType]: "application/json",
},
},
);
});
it("deleteNotebook", async () => {
const id = "id";
window.fetch = jest.fn().mockReturnValue({
status: HttpStatusCodes.OK,
json: () => undefined as undefined,
});
const response = await junoClient.deleteNotebook(id);
const authorizationHeader = getAuthorizationHeader();
expect(response.status).toBe(HttpStatusCodes.OK);
expect(window.fetch).toHaveBeenCalledWith(
`${JunoClient.getJunoEndpoint()}/api/notebooks/subscriptions/${sampleSubscriptionId}/databaseAccounts/${
sampleDatabaseAccount.name
}/gallery/${id}`,
{
method: "DELETE",
headers: {
[authorizationHeader.header]: authorizationHeader.token,
[HttpHeaders.contentType]: "application/json",
},
},
);
});
it("publishNotebook", async () => {
const name = "name";
const description = "description";
const tags = ["tag"];
const thumbnailUrl = "thumbnailUrl";
const content = `{ "key": "value" }`;
const addLinkToNotebookViewer = true;
window.fetch = jest.fn().mockReturnValue({
status: HttpStatusCodes.OK,
json: () => undefined as undefined,
});
const response = await junoClient.publishNotebook(name, description, tags, thumbnailUrl, content);
const authorizationHeader = getAuthorizationHeader();
expect(response.status).toBe(HttpStatusCodes.OK);
expect(window.fetch).toHaveBeenCalledWith(
`${JunoClient.getJunoEndpoint()}/api/notebooks/subscriptions/${sampleSubscriptionId}/databaseAccounts/${
sampleDatabaseAccount.name
}/gallery`,
{
method: "PUT",
headers: {
[authorizationHeader.header]: authorizationHeader.token,
[HttpHeaders.contentType]: "application/json",
},
body: JSON.stringify({
name,
description,
tags,
thumbnailUrl,
content: JSON.parse(content),
addLinkToNotebookViewer,
} as IPublishNotebookRequest),
},
);
});
});
-253
View File
@@ -44,30 +44,6 @@ export interface IGalleryItem {
pendingScanJobIds: string[];
}
export interface IPublicGalleryData {
metadata: IPublicGalleryMetaData;
notebooksData: IGalleryItem[];
}
export interface IPublicGalleryMetaData {
acceptedCodeOfConduct: boolean;
}
export interface IUserGallery {
favorites: string[];
published: string[];
}
// Only exported for unit test
export interface IPublishNotebookRequest {
name: string;
description: string;
tags: string[];
thumbnailUrl: string;
content: unknown;
addLinkToNotebookViewer: boolean;
}
export class JunoClient {
private cachedPinnedRepos: ko.Observable<IPinnedRepo[]>;
@@ -176,90 +152,6 @@ export class JunoClient {
};
}
public async getSampleNotebooks(): Promise<IJunoResponse<IGalleryItem[]>> {
return this.getNotebooks(`${this.getNotebooksUrl()}/gallery/samples`);
}
public async getPublicNotebooks(): Promise<IJunoResponse<IGalleryItem[]>> {
return this.getNotebooks(`${this.getNotebooksUrl()}/gallery/public`);
}
public async getPublicGalleryData(): Promise<IJunoResponse<IPublicGalleryData>> {
const url = `${this.getNotebooksSubscriptionIdAccountUrl()}/gallery/public`;
const response = await window.fetch(url, { headers: JunoClient.getHeaders() });
let data: IPublicGalleryData;
if (response.status === HttpStatusCodes.OK) {
data = await response.json();
}
return {
status: response.status,
data,
};
}
public async acceptCodeOfConduct(): Promise<IJunoResponse<boolean>> {
const url = `${this.getNotebooksSubscriptionIdAccountUrl()}/gallery/acceptCodeOfConduct`;
const response = await window.fetch(url, {
method: "PATCH",
headers: JunoClient.getHeaders(),
});
let data: boolean;
if (response.status === HttpStatusCodes.OK) {
data = await response.json();
}
return {
status: response.status,
data,
};
}
public async isCodeOfConductAccepted(): Promise<IJunoResponse<boolean>> {
const url = `${this.getNotebooksSubscriptionIdAccountUrl()}/gallery/isCodeOfConductAccepted`;
const response = await window.fetch(url, { headers: JunoClient.getHeaders() });
let data: boolean;
if (response.status === HttpStatusCodes.OK) {
data = await response.json();
}
return {
status: response.status,
data,
};
}
public async getNotebookInfo(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",
@@ -276,151 +168,6 @@ export class JunoClient {
};
}
public async increaseNotebookDownloadCount(id: string): Promise<IJunoResponse<IGalleryItem>> {
const response = await window.fetch(`${this.getNotebooksSubscriptionIdAccountUrl()}/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.getNotebooksSubscriptionIdAccountUrl()}/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.getNotebooksSubscriptionIdAccountUrl()}/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.getNotebooksSubscriptionIdAccountUrl()}/gallery/favorites`, {
headers: JunoClient.getHeaders(),
});
}
public async getPublishedNotebooks(): Promise<IJunoResponse<IGalleryItem[]>> {
return await this.getNotebooks(`${this.getNotebooksSubscriptionIdAccountUrl()}/gallery/published`, {
headers: JunoClient.getHeaders(),
});
}
public async deleteNotebook(id: string): Promise<IJunoResponse<IGalleryItem>> {
const response = await window.fetch(`${this.getNotebooksSubscriptionIdAccountUrl()}/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[],
thumbnailUrl: string,
content: string,
): Promise<IJunoResponse<IGalleryItem>> {
const response = await window.fetch(`${this.getNotebooksSubscriptionIdAccountUrl()}/gallery`, {
method: "PUT",
headers: JunoClient.getHeaders(),
body: JSON.stringify({
name,
description,
tags,
thumbnailUrl,
content: JSON.parse(content),
addLinkToNotebookViewer: true,
} as IPublishNotebookRequest),
});
let data: IGalleryItem;
if (response.status === HttpStatusCodes.OK) {
data = await response.json();
} else {
throw new Error(`HTTP status ${response.status} thrown. ${(await response.json()).Message}`);
}
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}`;
}
public async reportAbuse(notebookId: string, abuseCategory: string, notes: string): Promise<IJunoResponse<boolean>> {
const response = await window.fetch(`${this.getNotebooksUrl()}/gallery/reportAbuse`, {
method: "POST",
body: JSON.stringify({
notebookId,
abuseCategory,
notes,
}),
headers: {
[HttpHeaders.contentType]: "application/json",
},
});
let data: boolean;
if (response.status === HttpStatusCodes.OK) {
data = await response.json();
}
return {
status: response.status,
data,
};
}
public async requestSchema(
schemaRequest: DataModels.ISchemaRequest,
): Promise<IJunoResponse<DataModels.ISchemaRequest>> {