Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Disable /preview for unpublished flows #2792

Merged
merged 3 commits into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions editor.planx.uk/src/lib/dataMergedHotfix.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ComponentType as TYPES } from "@opensystemslab/planx-core/types";
import gql from "graphql-tag";
import { Store } from "pages/FlowEditor/lib/store";

import { publicClient } from "../lib/graphql";

Expand All @@ -23,10 +24,14 @@ const getFlowData = async (id: string) => {
// Flatten a flow's data to include main content & portals in a single JSON representation
// XXX: getFlowData & dataMerged are currently repeated in api.planx.uk/helpers.ts
// in order to load frontend /preview routes for flows that are not published
export const dataMerged = async (id: string, ob: Record<string, any> = {}) => {
export const dataMerged = async (
id: string,
ob: Store.flow = {},
): Promise<Store.flow> => {
// get the primary flow data
const { slug, data }: { slug: string; data: Record<string, any> } =
await getFlowData(id);
const { slug, data }: { slug: string; data: Store.flow } = await getFlowData(
id,
);

// recursively get and flatten internal portals & external portals
for (const [nodeId, node] of Object.entries(data)) {
Expand Down
45 changes: 29 additions & 16 deletions editor.planx.uk/src/pages/FlowEditor/components/PreviewBrowser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ const PreviewBrowser: React.FC<{
lastPublished,
lastPublisher,
validateAndDiffFlow,
isFlowPublished,
] = useStore((state) => [
state.id,
state.flowAnalyticsLink,
Expand All @@ -111,6 +112,7 @@ const PreviewBrowser: React.FC<{
state.lastPublished,
state.lastPublisher,
state.validateAndDiffFlow,
state.isFlowPublished,
]);
const [key, setKey] = useState<boolean>(false);
const [lastPublishedTitle, setLastPublishedTitle] = useState<string>(
Expand Down Expand Up @@ -189,17 +191,26 @@ const PreviewBrowser: React.FC<{
<OpenInNewIcon />
</Link>
</Tooltip>

<Tooltip arrow title="Open published service">
<Link
href={props.url + "?analytics=false"}
target="_blank"
rel="noopener noreferrer"
color="inherit"
>
<LanguageIcon />
</Link>
</Tooltip>
{isFlowPublished ? (
<Tooltip arrow title="Open published service">
<Link
href={props.url + "?analytics=false"}
target="_blank"
rel="noopener noreferrer"
color="inherit"
>
<LanguageIcon />
</Link>
</Tooltip>
) : (
<Tooltip arrow title="Flow not yet published">
<Box>
<Link component={"button"} disabled aria-disabled={true}>
<LanguageIcon />
</Link>
</Box>
</Tooltip>
)}
</Box>
<Box width="100%" mt={2}>
<Box display="flex" flexDirection="column" alignItems="flex-end">
Expand Down Expand Up @@ -283,12 +294,14 @@ const PreviewBrowser: React.FC<{
try {
setDialogOpen(false);
setLastPublishedTitle("Publishing changes...");
const publishedFlow = await publishFlow(flowId, summary);
const { alteredNodes, message } = await publishFlow(
flowId,
summary,
);
setLastPublishedTitle(
publishedFlow?.data.alteredNodes
? `Successfully published changes to ${publishedFlow.data.alteredNodes.length} node(s)`
: `${publishedFlow?.data?.message}` ||
"No new changes to publish",
alteredNodes
? `Successfully published changes to ${alteredNodes.length} node(s)`
: `${message}` || "No new changes to publish",
);
} catch (error) {
setLastPublishedTitle("Error trying to publish");
Expand Down
21 changes: 18 additions & 3 deletions editor.planx.uk/src/pages/FlowEditor/lib/store/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ export const editorUIStore: StateCreator<
},
});

interface PublishFlowResponse {
alteredNodes: Store.node[];
message: string;
}

export interface EditorStore extends Store.Store {
addNode: (node: any, relationships?: any) => void;
connect: (src: Store.nodeId, tgt: Store.nodeId, object?: any) => void;
Expand All @@ -67,6 +72,7 @@ export interface EditorStore extends Store.Store {
isClone: (id: Store.nodeId) => boolean;
lastPublished: (flowId: string) => Promise<string>;
lastPublisher: (flowId: string) => Promise<string>;
isFlowPublished: boolean;
makeUnique: (id: Store.nodeId, parent?: Store.nodeId) => void;
moveFlow: (flowId: string, teamSlug: string) => Promise<any>;
moveNode: (
Expand All @@ -76,7 +82,10 @@ export interface EditorStore extends Store.Store {
toParent?: Store.nodeId,
) => void;
pasteNode: (toParent: Store.nodeId, toBefore: Store.nodeId) => void;
publishFlow: (flowId: string, summary?: string) => Promise<any>;
publishFlow: (
flowId: string,
summary?: string,
) => Promise<PublishFlowResponse>;
removeNode: (id: Store.nodeId, parent: Store.nodeId) => void;
updateNode: (node: any, relationships?: any) => void;
}
Expand Down Expand Up @@ -325,6 +334,8 @@ export const editorStore: StateCreator<
return first_name.concat(" ", last_name);
},

isFlowPublished: false,

makeUnique: (id, parent) => {
const [, ops] = makeUnique(id, parent)(get().flow);
send(ops);
Expand Down Expand Up @@ -388,15 +399,15 @@ export const editorStore: StateCreator<
}
},

publishFlow(flowId: string, summary?: string) {
async publishFlow(flowId: string, summary?: string) {
const token = get().jwt;

const urlWithParams = (url: string, params: any) =>
[url, new URLSearchParams(omitBy(params, isEmpty))]
.filter(Boolean)
.join("?");

return axios.post(
const { data } = await axios.post<PublishFlowResponse>(
urlWithParams(
`${process.env.REACT_APP_API_URL}/flows/${flowId}/publish`,
{ summary },
Expand All @@ -408,6 +419,10 @@ export const editorStore: StateCreator<
},
},
);

set({ isFlowPublished: true });

return data;
},

removeNode: (id, parent) => {
Expand Down
51 changes: 40 additions & 11 deletions editor.planx.uk/src/routes/flow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
map,
Matcher,
mount,
NotFoundError,
redirect,
route,
withData,
Expand Down Expand Up @@ -173,11 +174,31 @@ const nodeRoutes = mount({
"/:parent/nodes/:id/edit": editNode,
});

interface FlowMetadata {
flowSettings: FlowSettings;
flowAnalyticsLink: string;
isFlowPublished: boolean;
}

interface GetFlowMetadata {
flows: {
flowSettings: FlowSettings;
flowAnalyticsLink: string;
publishedFlowsAggregate: {
aggregate: {
count: number;
};
};
}[];
}

const getFlowMetadata = async (
flow: string,
flowSlug: string,
team: string,
): Promise<{ flowSettings: FlowSettings; flowAnalyticsLink: string }> => {
const { data } = await client.query({
): Promise<FlowMetadata> => {
const {
data: { flows },
} = await client.query<GetFlowMetadata>({
query: gql`
query GetFlow($slug: String!, $team_slug: String!) {
flows(
Expand All @@ -187,17 +208,27 @@ const getFlowMetadata = async (
id
flowSettings: settings
flowAnalyticsLink: analytics_link
publishedFlowsAggregate: published_flows_aggregate {
aggregate {
count
}
}
}
}
`,
variables: {
slug: flow,
slug: flowSlug,
team_slug: team,
},
});

const flow = flows[0];
if (!flows) throw new NotFoundError(`Flow ${flowSlug} not found for ${team}`);

const metadata = {
flowSettings: data.flows[0]?.flowSettings,
flowAnalyticsLink: data.flows[0]?.flowAnalyticsLink,
flowSettings: flow.flowSettings,
flowAnalyticsLink: flow.flowAnalyticsLink,
isFlowPublished: flow.publishedFlowsAggregate?.aggregate.count > 0,
};
return metadata;
};
Expand All @@ -209,11 +240,9 @@ const routes = compose(

withView(async (req) => {
const [flow, ...breadcrumbs] = req.params.flow.split(",");
const { flowSettings, flowAnalyticsLink } = await getFlowMetadata(
flow,
req.params.team,
);
useStore.setState({ flowSettings, flowAnalyticsLink });
const { flowSettings, flowAnalyticsLink, isFlowPublished } =
await getFlowMetadata(flow, req.params.team);
useStore.setState({ flowSettings, flowAnalyticsLink, isFlowPublished });

return (
<>
Expand Down
11 changes: 4 additions & 7 deletions editor.planx.uk/src/routes/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import gql from "graphql-tag";
import { hasFeatureFlag } from "lib/featureFlags";
import { NaviRequest, NotFoundError } from "navi";
import { useStore } from "pages/FlowEditor/lib/store";
import { Store } from "pages/FlowEditor/lib/store";
import { ApplicationPath } from "types";

import { publicClient } from "../lib/graphql";
Expand All @@ -18,14 +19,10 @@ export const rootFlowPath = (includePortals = false) => {
export const rootTeamPath = () =>
window.location.pathname.split("/").slice(0, 2).join("/");

export const isSaveReturnFlow = (flowData: Record<string, any>): boolean =>
Boolean(
Object.values(flowData).find(
(node: Record<string, any>) => node.type === NodeTypes.Send,
),
);
export const isSaveReturnFlow = (flowData: Store.flow): boolean =>
Boolean(Object.values(flowData).find((node) => node.type === NodeTypes.Send));

export const setPath = (flowData: Record<string, any>, req: NaviRequest) => {
export const setPath = (flowData: Store.flow, req: NaviRequest) => {
// XXX: store.path is SingleSession by default
if (!isSaveReturnFlow(flowData)) return;
if (hasFeatureFlag("DISABLE_SAVE_AND_RETURN")) return;
Expand Down
15 changes: 9 additions & 6 deletions editor.planx.uk/src/routes/views/published.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import gql from "graphql-tag";
import { dataMerged } from "lib/dataMergedHotfix";
import { publicClient } from "lib/graphql";
import { NaviRequest } from "navi";
import { NotFoundError } from "navi";
import { useStore } from "pages/FlowEditor/lib/store";
import { Store } from "pages/FlowEditor/lib/store";
import PublicLayout from "pages/layout/PublicLayout";
import SaveAndReturnLayout from "pages/layout/SaveAndReturnLayout";
import React from "react";
Expand All @@ -17,7 +17,7 @@ interface PublishedViewData {
}

interface PreviewFlow extends Flow {
publishedFlows: Record<"data", Flow>[];
publishedFlows: Record<"data", Store.flow>[];
}

/**
Expand All @@ -31,16 +31,19 @@ export const publishedView = async (req: NaviRequest) => {
const data = await fetchDataForPublishedView(flowSlug, teamSlug);

const flow = data.flows[0];
if (!flow) throw new NotFoundError(req.originalUrl);
if (!flow)
throw new NotFoundError(`Flow ${flowSlug} not found for ${teamSlug}`);

const publishedFlow = flow.publishedFlows[0]?.data;
const flowData = publishedFlow ? publishedFlow : await dataMerged(flow.id);
setPath(flowData, req);
if (!publishedFlow)
throw new NotFoundError(`Flow ${flowSlug} not published for ${teamSlug}`);

setPath(publishedFlow, req);

const state = useStore.getState();
// XXX: necessary as long as not every flow is published; aim to remove dataMergedHotfix.ts in future
// load pre-flattened published flow if exists, else load & flatten flow
state.setFlow({ id: flow.id, flow: flowData, flowSlug });
state.setFlow({ id: flow.id, flow: publishedFlow, flowSlug });
state.setGlobalSettings(data.globalSettings[0]);
state.setFlowSettings(flow.settings);
state.setTeam(flow.team);
Expand Down
8 changes: 8 additions & 0 deletions hasura.planx.uk/metadata/tables.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,7 @@
computed_fields:
- data_merged
filter: {}
allow_aggregations: true
- role: platformAdmin
permission:
columns:
Expand All @@ -441,6 +442,7 @@
computed_fields:
- data_merged
filter: {}
allow_aggregations: true
- role: public
permission:
columns:
Expand All @@ -456,6 +458,7 @@
computed_fields:
- data_merged
filter: {}
allow_aggregations: true
- role: teamEditor
permission:
columns:
Expand All @@ -472,6 +475,7 @@
computed_fields:
- data_merged
filter: {}
allow_aggregations: true
update_permissions:
- role: api
permission:
Expand Down Expand Up @@ -1230,6 +1234,7 @@
- flow_id
- data
filter: {}
allow_aggregations: true
- role: platformAdmin
permission:
columns:
Expand All @@ -1240,6 +1245,7 @@
- publisher_id
- summary
filter: {}
allow_aggregations: true
- role: public
permission:
columns:
Expand All @@ -1250,6 +1256,7 @@
- publisher_id
- summary
filter: {}
allow_aggregations: true
- role: teamEditor
permission:
columns:
Expand All @@ -1260,6 +1267,7 @@
- publisher_id
- summary
filter: {}
allow_aggregations: true
- table:
name: reconciliation_requests
schema: public
Expand Down
Loading