Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | 216642x 215082x 1200x 135x 100x 106x 7x 7x 7x 541x 12452x 12452x 12452x 12452x 12452x 52306x 11382x 10183x 5724x 4336x 123x 47x 1023x 103x 12993x 11654x 1337x 2x 2x 2x | import type { FlowsheetAccess, FlowsheetRead } from "@/api/apiStore.gen";
export type FlowsheetWithAccess = Omit<FlowsheetRead, "access"> & {
access?: FlowsheetAccess;
};
export type SharedUserAccess = {
email: string;
read_only: boolean;
};
export function getFlowsheetAccess(
project?: FlowsheetRead,
): FlowsheetAccess | undefined {
return (project as FlowsheetWithAccess | undefined)?.access;
}
/** Derive immutable preview capabilities without changing cached access data. */
export function deriveRevisionPreviewAccess(
access: FlowsheetAccess | undefined,
revisionSelected: boolean,
): FlowsheetAccess | undefined {
if (!revisionSelected) {
return access;
}
if (access) {
return {
...access,
read_only: true,
can_edit: false,
};
}
return {
is_owner: false,
read_only: true,
can_edit: false,
can_share: false,
can_copy: false,
can_export: false,
can_manage_template_settings: false,
};
}
export function normalizeSharedUsers(users: unknown): SharedUserAccess[] {
if (!Array.isArray(users)) {
return [];
}
return users.flatMap((user) => {
if (!user || typeof user !== "object") {
return [];
}
const email = "email" in user ? user.email : undefined;
const readOnly = "read_only" in user ? user.read_only : undefined;
if (typeof email !== "string") {
return [];
}
return [{ email, read_only: Boolean(readOnly) }];
});
}
export function getCachedFlowsheetAccess(
state: Record<string, unknown> | undefined,
reducerPath: string,
flowsheetId: number | null,
): FlowsheetAccess | undefined {
if (!state || !reducerPath || !flowsheetId) {
return undefined;
}
const reducerState = state[reducerPath];
const queries =
reducerState && typeof reducerState === "object"
? (reducerState as { queries?: unknown }).queries
: undefined;
if (!queries || typeof queries !== "object") {
return undefined;
}
const directQueryPrefix = `coreFlowsheetsRetrieve({"id":"${flowsheetId}"})`;
const queryEntries = Object.entries(
queries as Record<string, { data?: unknown }>,
);
const directData = queryEntries.find(([queryKey]) =>
queryKey.startsWith(directQueryPrefix),
)?.[1]?.data as FlowsheetWithAccess | undefined;
if (directData?.access) {
return directData.access;
}
// Some screens only have the flowsheet cached via list-style queries, so fall
// back to scanning the RTK Query cache instead of requiring a dedicated detail
// fetch before the UI can decide whether to disable mutation controls.
for (const [, value] of queryEntries) {
const data = (value as { data?: unknown } | undefined)?.data;
if (!data || typeof data !== "object") {
continue;
}
if ((data as { id?: unknown }).id !== flowsheetId) {
continue;
}
const access = (data as FlowsheetWithAccess).access;
if (access) {
return access;
}
}
return undefined;
}
const READ_ONLY_ALLOWED_MUTATION_PATH_SEGMENTS = [
"/api/flowsheet/copy",
"/download",
"/download_",
"/export",
];
export function isReadOnlyMutationBlocked({
method,
pathname,
access,
}: {
method: string;
pathname: string;
access?: FlowsheetAccess;
}) {
const normalizedMethod = method.toUpperCase();
if (
normalizedMethod === "GET" ||
normalizedMethod === "HEAD" ||
normalizedMethod === "OPTIONS"
) {
return false;
}
if (!access?.read_only) {
return false;
}
const normalizedPath = pathname.toLowerCase();
// Copy / download / export are intentionally still allowed for read-only
// shares, because they do not mutate the shared source flowsheet itself.
return !READ_ONLY_ALLOWED_MUTATION_PATH_SEGMENTS.some((segment) =>
normalizedPath.includes(segment),
);
}
|