Skip to content
Snippets Groups Projects
Unverified Commit 17e20c17 authored by Anton Kulyk's avatar Anton Kulyk Committed by GitHub
Browse files

Allow archiving apps (#25580)

* Remove collection actions not suitable for apps

* Allow archiving apps
parent 0967b7cb
No related merge requests found
......@@ -27,4 +27,5 @@ export type GetState = () => State;
export type ReduxAction<Type = string, Payload = any> = {
type: Type;
payload: Payload;
error?: string;
};
......@@ -2,8 +2,6 @@ import React from "react";
import { withRouter } from "react-router";
import type { Location } from "history";
import * as Urls from "metabase/lib/urls";
import { isDataAppCollection } from "metabase/entities/data-apps";
import { Collection } from "metabase-types/api";
......@@ -37,6 +35,8 @@ const CollectionHeader = ({
onCreateBookmark,
onDeleteBookmark,
}: CollectionHeaderProps): JSX.Element => {
const isDataApp = isDataAppCollection(collection);
return (
<HeaderRoot>
<CollectionCaption
......@@ -44,10 +44,7 @@ const CollectionHeader = ({
onUpdateCollection={onUpdateCollection}
/>
<HeaderActions data-testid="collection-menu">
{isDataAppCollection(collection) &&
Urls.isDataAppPreviewPath(location.pathname) && (
<LaunchDataAppButton collection={collection} />
)}
{isDataApp && <LaunchDataAppButton collection={collection} />}
<CollectionTimeline collection={collection} />
<CollectionBookmark
collection={collection}
......@@ -58,6 +55,7 @@ const CollectionHeader = ({
<CollectionMenu
collection={collection}
isAdmin={isAdmin}
isDataApp={isDataApp}
isPersonalCollectionChild={isPersonalCollectionChild}
onUpdateCollection={onUpdateCollection}
/>
......
import React from "react";
import { t } from "ttag";
import _ from "underscore";
import { PLUGIN_COLLECTIONS } from "metabase/plugins";
import * as Urls from "metabase/lib/urls";
import EntityMenu from "metabase/components/EntityMenu";
......@@ -14,6 +16,7 @@ export interface CollectionMenuProps {
collection: Collection;
isAdmin: boolean;
isPersonalCollectionChild: boolean;
isDataApp: boolean;
onUpdateCollection: (entity: Collection, values: Partial<Collection>) => void;
}
......@@ -21,10 +24,13 @@ const CollectionMenu = ({
collection,
isAdmin,
isPersonalCollectionChild,
isDataApp,
onUpdateCollection,
}: CollectionMenuProps): JSX.Element | null => {
const items = [];
const url = Urls.collection(collection);
const url = isDataApp
? Urls.collection(_.omit(collection, "app_id"))
: Urls.collection(collection);
const isRoot = isRootCollection(collection);
const isPersonal = isPersonalCollection(collection);
const canWrite = collection.can_write;
......@@ -38,7 +44,7 @@ const CollectionMenu = ({
);
}
if (isAdmin && !isPersonal && !isPersonalCollectionChild) {
if (isAdmin && !isPersonal && !isPersonalCollectionChild && !isDataApp) {
items.push({
title: t`Edit permissions`,
icon: "lock",
......@@ -48,20 +54,20 @@ const CollectionMenu = ({
}
if (!isRoot && !isPersonal && canWrite) {
items.push(
{
if (!isDataApp) {
items.push({
title: t`Move`,
icon: "move",
link: `${url}/move`,
event: `${ANALYTICS_CONTEXT};Edit Menu;Move Collection`,
},
{
title: t`Archive`,
icon: "archive",
link: `${url}/archive`,
event: `${ANALYTICS_CONTEXT};Edit Menu;Archive Collection`,
},
);
});
}
items.push({
title: t`Archive`,
icon: "archive",
link: `${url}/archive`,
event: `${ANALYTICS_CONTEXT};Edit Menu;Archive Collection`,
});
}
if (items.length > 0) {
......
......@@ -10,6 +10,7 @@ import { Collection, DataApp, DataAppSearchItem } from "metabase-types/api";
import { DEFAULT_COLLECTION_COLOR_ALIAS } from "../collections/constants";
import { createNewAppForm, createAppSettingsForm } from "./forms";
import reducer from "./reducer";
import { getDataAppIcon } from "./utils";
type EditableDataAppParams = Pick<
......@@ -109,6 +110,8 @@ const DataApps = createEntity({
fields: createAppSettingsForm,
},
},
reducer,
});
export * from "./utils";
......
import _ from "underscore";
import Collections from "metabase/entities/collections";
import type {
Collection,
RegularCollectionId,
DataApp,
DataAppId,
} from "metabase-types/api";
import type { ReduxAction } from "metabase-types/store";
type CollectionUpdateActionPayload = {
collection: Collection;
object: Collection;
entities: {
collections: Record<RegularCollectionId, Collection>;
};
};
type NormalizedDataApp = Omit<DataApp, "collection">;
type DataAppsState = {
[id: DataAppId]: NormalizedDataApp;
};
function reducer(
state: DataAppsState = {},
{ type, payload, error }: ReduxAction,
) {
if (type === Collections.actionTypes.UPDATE && !error) {
const { collection } = payload as CollectionUpdateActionPayload;
if (collection.archived) {
const apps = Object.values(state);
const app = _.findWhere(apps, { collection_id: collection.id as number });
return app ? _.omit(state, app.id as any) : state;
}
}
return state;
}
export default reducer;
import {
createMockDataApp,
createMockCollection,
} from "metabase-types/api/mocks";
import type { Collection } from "metabase-types/api";
import Collections from "../collections";
import DataApps from "./data-apps";
function getCollectionUpdateAction({
collection,
error,
}: {
collection: Collection;
error?: string;
}) {
return {
type: Collections.actionTypes.UPDATE,
payload: {
collection,
object: collection,
entities: {
[collection.id]: collection,
},
},
error,
};
}
describe("entities > data apps > reducer", () => {
describe("archiving", () => {
const collection = createMockCollection({ id: 5 });
const dataApp = createMockDataApp({ id: 1, collection });
const state = { [dataApp.id]: dataApp };
it("should remove data app when underlying collection is archived", () => {
const anotherDataApp = createMockDataApp({ id: 2 });
const nextState = DataApps.reducer(
{ ...state, [anotherDataApp.id]: anotherDataApp },
getCollectionUpdateAction({
collection: { ...collection, archived: true },
}),
);
expect(nextState).toEqual({ [anotherDataApp.id]: anotherDataApp });
});
it("should ignore failed update actions", () => {
const nextState = DataApps.reducer(
state,
getCollectionUpdateAction({
collection: { ...collection, archived: true },
error: "Something went wrong",
}),
);
expect(nextState).toEqual(state);
});
});
});
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment