Skip to content

Commit 46db1b2

Browse files
committed
added hasLogsPageAccess featureFlag for logs page
1 parent 78b3493 commit 46db1b2

File tree

5 files changed

+40
-16
lines changed

5 files changed

+40
-16
lines changed

apps/webapp/app/components/navigation/SideMenu.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ export function SideMenu({
269269
to={v3DeploymentsPath(organization, project, environment)}
270270
data-action="deployments"
271271
/>
272-
{(isAdmin || user.isImpersonating) && (
272+
{(user.admin || user.isImpersonating || featureFlags.hasLogsPageAccess) && (
273273
<SideMenuItem
274274
name="Logs"
275275
icon={LogsIcon}

apps/webapp/app/presenters/v3/LogDetailPresenter.server.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,6 @@ export class LogDetailPresenter {
3636
);
3737
}
3838

39-
// Throw error if clickhouse v1 is detected (not supported)
40-
if (store === "postgres") {
41-
throw new ServiceValidationError(
42-
"Log details are not available for postgres event store. Please contact support."
43-
);
44-
}
45-
4639
// Build ClickHouse query - only v2 is supported for log details
4740
const isClickhouseV2 = store === "clickhouse_v2";
4841
const queryBuilder = isClickhouseV2

apps/webapp/app/presenters/v3/LogsListPresenter.server.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -375,13 +375,6 @@ export class LogsListPresenter extends BasePresenter {
375375
);
376376
}
377377

378-
// Throw error if clickhouse v1 is detected (not supported)
379-
if (store === "postgres") {
380-
throw new ServiceValidationError(
381-
"Logs are not available for Postgres event store. Please contact support."
382-
);
383-
}
384-
385378
// Get the appropriate query builder based on store type
386379
const isClickhouseV2 = store === "clickhouse_v2";
387380

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.logs/route.tsx

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { findEnvironmentBySlug } from "~/models/runtimeEnvironment.server";
1515
import { getRunFiltersFromRequest } from "~/presenters/RunFilters.server";
1616
import { LogsListPresenter } from "~/presenters/v3/LogsListPresenter.server";
1717
import type { LogLevel } from "~/utils/logUtils";
18-
import { $replica } from "~/db.server";
18+
import { $replica, prisma } from "~/db.server";
1919
import { clickhouseClient } from "~/services/clickhouseInstance.server";
2020
import {
2121
setRootOnlyFilterPreference,
@@ -39,6 +39,7 @@ import {
3939
ResizablePanelGroup,
4040
} from "~/components/primitives/Resizable";
4141
import { Switch } from "~/components/primitives/Switch";
42+
import { FEATURE_FLAG, validateFeatureFlagValue } from "~/v3/featureFlags.server";
4243

4344
// Valid log levels for filtering
4445
const validLevels: LogLevel[] = ["TRACE", "DEBUG", "INFO", "WARN", "ERROR", "CANCELLED"];
@@ -57,6 +58,41 @@ export const meta: MetaFunction = () => {
5758
];
5859
};
5960

61+
async function hasLogsPageAccess(
62+
userId: string,
63+
isAdmin: boolean,
64+
isImpersonating: boolean,
65+
organizationSlug: string
66+
): Promise<boolean> {
67+
if (isAdmin || isImpersonating) {
68+
return true;
69+
}
70+
71+
// Check organization feature flags
72+
const organization = await prisma.organization.findFirst({
73+
where: {
74+
slug: organizationSlug,
75+
members: { some: { userId } },
76+
},
77+
select: {
78+
featureFlags: true,
79+
},
80+
});
81+
82+
if (!organization?.featureFlags) {
83+
return false;
84+
}
85+
86+
const flags = organization.featureFlags as Record<string, unknown>;
87+
const hasLogsPageAccessResult = validateFeatureFlagValue(
88+
FEATURE_FLAG.hasLogsPageAccess,
89+
flags.hasLogsPageAccess
90+
);
91+
92+
return hasLogsPageAccessResult.success && hasLogsPageAccessResult.data === true;
93+
}
94+
95+
6096
export const loader = async ({ request, params }: LoaderFunctionArgs) => {
6197
const user = await requireUser(request);
6298
const userId = user.id;

apps/webapp/app/v3/featureFlags.server.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@ export const FEATURE_FLAG = {
66
runsListRepository: "runsListRepository",
77
taskEventRepository: "taskEventRepository",
88
hasQueryAccess: "hasQueryAccess",
9+
hasLogsPageAccess: "hasLogsPageAccess",
910
} as const;
1011

1112
const FeatureFlagCatalog = {
1213
[FEATURE_FLAG.defaultWorkerInstanceGroupId]: z.string(),
1314
[FEATURE_FLAG.runsListRepository]: z.enum(["clickhouse", "postgres"]),
1415
[FEATURE_FLAG.taskEventRepository]: z.enum(["clickhouse", "clickhouse_v2", "postgres"]),
1516
[FEATURE_FLAG.hasQueryAccess]: z.coerce.boolean(),
17+
[FEATURE_FLAG.hasLogsPageAccess]: z.coerce.boolean(),
1618
};
1719

1820
type FeatureFlagKey = keyof typeof FeatureFlagCatalog;

0 commit comments

Comments
 (0)