Hide pages in publish mode (#3106)
This commit is contained in:
parent
cccdd89b14
commit
7fa5e3b1af
|
|
@ -0,0 +1,21 @@
|
|||
const pages = require("../../../../locators/Pages.json");
|
||||
|
||||
const pageOne = "MyPage1";
|
||||
const pageTwo = "MyPage2";
|
||||
|
||||
describe("Hide page", function() {
|
||||
it("Hide page", function() {
|
||||
cy.Createpage(pageOne);
|
||||
cy.Createpage(pageTwo);
|
||||
|
||||
cy.GlobalSearchEntity(pageOne);
|
||||
cy.xpath(pages.popover)
|
||||
.last()
|
||||
.click({ force: true });
|
||||
cy.get(pages.hidePage).click({ force: true });
|
||||
cy.ClearSearch();
|
||||
|
||||
cy.PublishtheApp();
|
||||
cy.get(".t--page-switch-tab").should("have.length", 2);
|
||||
});
|
||||
});
|
||||
|
|
@ -7,6 +7,7 @@ describe("Page Load tests", () => {
|
|||
cy.get("div")
|
||||
.contains("Pages")
|
||||
.next()
|
||||
.next()
|
||||
.click();
|
||||
cy.get("h2").contains("Drag and drop a widget here");
|
||||
cy.addDsl(dsl);
|
||||
|
|
|
|||
|
|
@ -18,5 +18,6 @@
|
|||
"editName": ".single-select >div:contains('Edit Name')",
|
||||
"clonePage": ".single-select >div:contains('Clone')",
|
||||
"deletePage": ".single-select >div:contains('Delete')",
|
||||
"hidePage": ".single-select >div:contains('Hide')",
|
||||
"entityQuery": ".t--entity-name:contains('Queries')"
|
||||
}
|
||||
|
|
@ -155,12 +155,13 @@ export const clonePageSuccess = (
|
|||
};
|
||||
};
|
||||
|
||||
export const updatePage = (id: string, name: string) => {
|
||||
export const updatePage = (id: string, name: string, isHidden: boolean) => {
|
||||
return {
|
||||
type: ReduxActionTypes.UPDATE_PAGE_INIT,
|
||||
payload: {
|
||||
id,
|
||||
name,
|
||||
isHidden,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ export interface CreatePageRequest {
|
|||
export interface UpdatePageRequest {
|
||||
id: string;
|
||||
name: string;
|
||||
isHidden?: boolean;
|
||||
}
|
||||
|
||||
export interface CreatePageResponse extends ApiResponse {
|
||||
|
|
@ -78,6 +79,7 @@ export interface FetchPageListResponse extends ApiResponse {
|
|||
id: string;
|
||||
name: string;
|
||||
isDefault: boolean;
|
||||
isHidden?: boolean;
|
||||
layouts: Array<PageLayout>;
|
||||
}>;
|
||||
organizationId: string;
|
||||
|
|
|
|||
|
|
@ -503,6 +503,7 @@ export interface Page {
|
|||
pageId: string;
|
||||
isDefault: boolean;
|
||||
latest?: boolean;
|
||||
isHidden?: boolean;
|
||||
}
|
||||
|
||||
export interface ClonePageSuccessPayload {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import {
|
|||
import { editorInitializer } from "utils/EditorUtils";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import log from "loglevel";
|
||||
import { getPageList } from "selectors/editorSelectors";
|
||||
import { getViewModePageList } from "selectors/editorSelectors";
|
||||
|
||||
const SentryRoute = Sentry.withSentryRouting(Route);
|
||||
|
||||
|
|
@ -111,7 +111,7 @@ class AppViewer extends Component<
|
|||
|
||||
const mapStateToProps = (state: AppState) => ({
|
||||
isInitialized: getIsInitialized(state),
|
||||
pages: getPageList(state),
|
||||
pages: getViewModePageList(state),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch: any) => ({
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import {
|
|||
import { connect } from "react-redux";
|
||||
import { AppState } from "reducers";
|
||||
import { getEditorURL } from "selectors/appViewSelectors";
|
||||
import { getPageList } from "selectors/editorSelectors";
|
||||
import { getViewModePageList } from "selectors/editorSelectors";
|
||||
import { FormDialogComponent } from "components/editorComponents/form/FormDialogComponent";
|
||||
import AppInviteUsersForm from "pages/organization/AppInviteUsersForm";
|
||||
import { getCurrentOrgId } from "selectors/organizationSelectors";
|
||||
|
|
@ -135,7 +135,7 @@ type AppViewerHeaderProps = {
|
|||
};
|
||||
|
||||
export const AppViewerHeader = (props: AppViewerHeaderProps) => {
|
||||
const { currentApplicationDetails, pages, currentOrgId, currentUser } = props;
|
||||
const { currentApplicationDetails, currentOrgId, currentUser, pages } = props;
|
||||
const isExampleApp = currentApplicationDetails?.appIsExample;
|
||||
const userPermissions = currentApplicationDetails?.userPermissions ?? [];
|
||||
const permissionRequired = PERMISSION_TYPE.MANAGE_APPLICATION;
|
||||
|
|
@ -249,7 +249,7 @@ export const AppViewerHeader = (props: AppViewerHeaderProps) => {
|
|||
};
|
||||
|
||||
const mapStateToProps = (state: AppState): AppViewerHeaderProps => ({
|
||||
pages: getPageList(state),
|
||||
pages: getViewModePageList(state),
|
||||
url: getEditorURL(state),
|
||||
currentApplicationDetails: state.ui.applications.currentApplication,
|
||||
currentOrgId: getCurrentOrgId(state),
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ const Wrapper = styled(EntityTogglesWrapper)`
|
|||
|
||||
const StyledEntity = styled(Entity)`
|
||||
& > div {
|
||||
grid-template-columns: 20px auto 1fr auto;
|
||||
grid-template-columns: 20px auto 1fr auto auto;
|
||||
}
|
||||
`;
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import useClick from "utils/hooks/useClick";
|
|||
|
||||
export enum EntityClassNames {
|
||||
CONTEXT_MENU = "entity-context-menu",
|
||||
RIGHT_ICON = "entity-right-icon",
|
||||
ADD_BUTTON = "t--entity-add-btn",
|
||||
NAME = "t--entity-name",
|
||||
COLLAPSE_TOGGLE = "t--entity-collapse-toggle",
|
||||
|
|
@ -44,7 +45,7 @@ export const EntityItem = styled.div<{
|
|||
width: 100%;
|
||||
display: inline-grid;
|
||||
grid-template-columns: ${(props) =>
|
||||
props.spaced ? "20px auto 1fr 30px" : "8px auto 1fr 30px"};
|
||||
props.spaced ? "20px auto 1fr auto 30px" : "8px auto 1fr auto 30px"};
|
||||
border-radius: 0;
|
||||
color: ${(props) => (props.active ? Colors.WHITE : Colors.ALTO)};
|
||||
cursor: pointer;
|
||||
|
|
@ -71,6 +72,14 @@ export const EntityItem = styled.div<{
|
|||
&&&&:hover .${EntityClassNames.CONTEXT_MENU} {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
& .${EntityClassNames.RIGHT_ICON} {
|
||||
visibility: hidden;
|
||||
padding-right: ${(props) => props.theme.spaces[2]}px;
|
||||
}
|
||||
&:hover .${EntityClassNames.RIGHT_ICON} {
|
||||
visibility: visible;
|
||||
}
|
||||
`;
|
||||
|
||||
const IconWrapper = styled.span`
|
||||
|
|
@ -83,6 +92,7 @@ export type EntityProps = {
|
|||
name: string;
|
||||
children?: ReactNode;
|
||||
icon: ReactNode;
|
||||
rightIcon?: ReactNode;
|
||||
disabled?: boolean;
|
||||
action?: () => void;
|
||||
active?: boolean;
|
||||
|
|
@ -172,6 +182,9 @@ export const Entity = forwardRef(
|
|||
updateEntityName={updateNameCallback}
|
||||
searchKeyword={props.searchKeyword}
|
||||
/>
|
||||
<IconWrapper className={EntityClassNames.RIGHT_ICON}>
|
||||
{props.rightIcon}
|
||||
</IconWrapper>
|
||||
<AddButton
|
||||
onClick={props.onCreate}
|
||||
className={`${EntityClassNames.ADD_BUTTON}`}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,10 @@ export const homePageIcon = (
|
|||
<Icon icon="home" iconSize={ENTITY_ICON_SIZE} color={Colors.JUNGLE_GREEN} />
|
||||
);
|
||||
|
||||
export const hiddenPageIcon = (
|
||||
<Icon icon="eye-off" iconSize={ENTITY_ICON_SIZE} color={Colors.ALTO} />
|
||||
);
|
||||
|
||||
const WidgetIcon = MenuIcons.WIDGETS_COLORED_ICON;
|
||||
export const widgetIcon = (
|
||||
<WidgetIcon width={ENTITY_ICON_SIZE} height={ENTITY_ICON_SIZE} keepColors />
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useCallback } from "react";
|
||||
import React, { ReactNode, useCallback } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import TreeDropdown, {
|
||||
TreeDropdownOption,
|
||||
|
|
@ -9,7 +9,15 @@ import { ReduxActionTypes } from "constants/ReduxActionConstants";
|
|||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||
import { ContextMenuPopoverModifiers } from "../helpers";
|
||||
import { initExplorerEntityNameEdit } from "actions/explorerActions";
|
||||
import { clonePageInit } from "actions/pageActions";
|
||||
import { clonePageInit, updatePage } from "actions/pageActions";
|
||||
import styled from "styled-components";
|
||||
import { Icon } from "@blueprintjs/core";
|
||||
|
||||
const CustomLabel = styled.div`
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
export const PageContextMenu = (props: {
|
||||
pageId: string;
|
||||
|
|
@ -17,6 +25,7 @@ export const PageContextMenu = (props: {
|
|||
applicationId: string;
|
||||
className?: string;
|
||||
isDefaultPage: boolean;
|
||||
isHidden: boolean;
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
|
|
@ -58,6 +67,11 @@ export const PageContextMenu = (props: {
|
|||
props.pageId,
|
||||
]);
|
||||
|
||||
const setHiddenField = useCallback(
|
||||
() => dispatch(updatePage(props.pageId, props.name, !props.isHidden)),
|
||||
[dispatch, props.pageId, props.name, props.isHidden],
|
||||
);
|
||||
|
||||
const optionTree: TreeDropdownOption[] = [
|
||||
{
|
||||
value: "rename",
|
||||
|
|
@ -69,6 +83,17 @@ export const PageContextMenu = (props: {
|
|||
onSelect: clonePage,
|
||||
label: "Clone",
|
||||
},
|
||||
{
|
||||
value: "visibility",
|
||||
onSelect: setHiddenField,
|
||||
// Possibly support ReactNode in TreeOption
|
||||
label: ((
|
||||
<CustomLabel>
|
||||
{props.isHidden ? "Show" : "Hide"}
|
||||
<Icon icon={props.isHidden ? "eye-open" : "eye-off"} iconSize={14} />
|
||||
</CustomLabel>
|
||||
) as ReactNode) as string,
|
||||
},
|
||||
];
|
||||
if (!props.isDefaultPage) {
|
||||
optionTree.push({
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { memo, useCallback } from "react";
|
||||
import React, { useCallback } from "react";
|
||||
import { Page } from "constants/ReduxActionConstants";
|
||||
import Entity, { EntityClassNames } from "../Entity";
|
||||
import { useParams } from "react-router";
|
||||
|
|
@ -10,7 +10,7 @@ import PageContextMenu from "./PageContextMenu";
|
|||
import { useSelector } from "react-redux";
|
||||
import { AppState } from "reducers";
|
||||
import { DataTreeAction } from "entities/DataTree/dataTreeFactory";
|
||||
import { homePageIcon, pageIcon } from "../ExplorerIcons";
|
||||
import { hiddenPageIcon, homePageIcon, pageIcon } from "../ExplorerIcons";
|
||||
import { getPluginGroups } from "../Actions/helpers";
|
||||
import ExplorerWidgetGroup from "../Widgets/WidgetGroup";
|
||||
import { resolveAsSpaceChar } from "utils/helpers";
|
||||
|
|
@ -28,7 +28,8 @@ type ExplorerPageEntityProps = {
|
|||
searchKeyword?: string;
|
||||
showWidgetsSidebar: (pageId: string) => void;
|
||||
};
|
||||
export const ExplorerPageEntity = memo((props: ExplorerPageEntityProps) => {
|
||||
|
||||
export const ExplorerPageEntity = (props: ExplorerPageEntityProps) => {
|
||||
const params = useParams<ExplorerURLParams>();
|
||||
|
||||
const currentPageId = useSelector((state: AppState) => {
|
||||
|
|
@ -50,10 +51,12 @@ export const ExplorerPageEntity = memo((props: ExplorerPageEntityProps) => {
|
|||
name={props.page.pageName}
|
||||
className={EntityClassNames.CONTEXT_MENU}
|
||||
isDefaultPage={props.page.isDefault}
|
||||
isHidden={!!props.page.isHidden}
|
||||
/>
|
||||
);
|
||||
|
||||
const icon = props.page.isDefault ? homePageIcon : pageIcon;
|
||||
const rightIcon = !!props.page.isHidden ? hiddenPageIcon : null;
|
||||
|
||||
const addWidgetsFn = useCallback(
|
||||
() => props.showWidgetsSidebar(props.page.pageId),
|
||||
|
|
@ -70,9 +73,12 @@ export const ExplorerPageEntity = memo((props: ExplorerPageEntityProps) => {
|
|||
entityId={props.page.pageId}
|
||||
active={isCurrentPage}
|
||||
isDefaultExpanded={isCurrentPage || !!props.searchKeyword}
|
||||
updateEntityName={updatePage}
|
||||
updateEntityName={(id, name) =>
|
||||
updatePage(id, name, !!props.page.isHidden)
|
||||
}
|
||||
contextMenu={contextMenu}
|
||||
onNameEdit={resolveAsSpaceChar}
|
||||
rightIcon={rightIcon}
|
||||
searchKeyword={props.searchKeyword}
|
||||
>
|
||||
<ExplorerWidgetGroup
|
||||
|
|
@ -93,7 +99,7 @@ export const ExplorerPageEntity = memo((props: ExplorerPageEntityProps) => {
|
|||
)}
|
||||
</Entity>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
ExplorerPageEntity.displayName = "ExplorerPageEntity";
|
||||
(ExplorerPageEntity as any).whyDidYouRender = {
|
||||
|
|
|
|||
|
|
@ -93,12 +93,13 @@ export const pageListReducer = createReducer(initialState, {
|
|||
}),
|
||||
[ReduxActionTypes.UPDATE_PAGE_SUCCESS]: (
|
||||
state: PageListReduxState,
|
||||
action: ReduxAction<{ id: string; name: string }>,
|
||||
action: ReduxAction<{ id: string; name: string; isHidden?: boolean }>,
|
||||
) => {
|
||||
const pages = [...state.pages];
|
||||
const updatedPage = pages.find((page) => page.pageId === action.payload.id);
|
||||
if (updatedPage) {
|
||||
updatedPage.pageName = action.payload.name;
|
||||
updatedPage.isHidden = !!action.payload.isHidden;
|
||||
}
|
||||
return { ...state, pages };
|
||||
},
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ export function* publishApplicationSaga(
|
|||
|
||||
const applicationId = yield select(getCurrentApplicationId);
|
||||
const currentPageId = yield select(getCurrentPageId);
|
||||
|
||||
let appicationViewPageUrl = getApplicationViewerPageURL(
|
||||
applicationId,
|
||||
currentPageId,
|
||||
|
|
@ -99,8 +100,9 @@ export function* publishApplicationSaga(
|
|||
if (!windowReference || windowReference.closed) {
|
||||
windowReference = window.open(appicationViewPageUrl, "_blank");
|
||||
} else {
|
||||
windowReference.location.reload();
|
||||
windowReference.focus();
|
||||
windowReference.location.href =
|
||||
windowReference.location.origin + appicationViewPageUrl;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@ export function* fetchPageListSaga(
|
|||
pageName: page.name,
|
||||
pageId: page.id,
|
||||
isDefault: page.isDefault,
|
||||
isHidden: !!page.isHidden,
|
||||
}));
|
||||
yield put({
|
||||
type: ReduxActionTypes.SET_CURRENT_ORG_ID,
|
||||
|
|
|
|||
|
|
@ -85,6 +85,26 @@ export const getCurrentPageId = (state: AppState) =>
|
|||
export const getCurrentApplicationId = (state: AppState) =>
|
||||
state.entities.pageList.applicationId;
|
||||
|
||||
export const getViewModePageList = createSelector(
|
||||
getPageList,
|
||||
getCurrentPageId,
|
||||
(pageList: PageListReduxState["pages"], currentPageId?: string) => {
|
||||
if (currentPageId) {
|
||||
const currentPage = pageList.find(
|
||||
(page) => page.pageId === currentPageId,
|
||||
);
|
||||
if (!!currentPage?.isHidden) {
|
||||
return [currentPage];
|
||||
}
|
||||
|
||||
const visiblePages = pageList.filter((page) => !page.isHidden);
|
||||
return visiblePages;
|
||||
}
|
||||
|
||||
return [];
|
||||
},
|
||||
);
|
||||
|
||||
export const getCurrentPageName = createSelector(
|
||||
getPageListState,
|
||||
(pageList: PageListReduxState) =>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user