5447cf4843
Adds a dialog to the admin orgs page for viewing and editing per-org feature flag overrides. Flags are introspected from the catalog so the UI stays in sync with available flags automatically. Also adds a new tab for global flags. Refactors featureFlags.server.ts to split catalog definition (shared) from server-only runtime (flags(), makeSetMultipleFlags). The shared module exports flag metadata and validation so both the UI and API routes can use it without pulling in server dependencies.
49 lines
1.2 KiB
TypeScript
49 lines
1.2 KiB
TypeScript
import { prisma } from "~/db.server";
|
|
import { env } from "~/env.server";
|
|
import { FEATURE_FLAG } from "~/v3/featureFlags";
|
|
import { makeFlag } from "~/v3/featureFlags.server";
|
|
|
|
export async function canAccessQuery(options: {
|
|
userId: string;
|
|
isAdmin: boolean;
|
|
isImpersonating: boolean;
|
|
organizationSlug: string;
|
|
}): Promise<boolean> {
|
|
const { userId, isAdmin, isImpersonating, organizationSlug } = options;
|
|
|
|
// 1. If it's on then we have access
|
|
const globallyEnabled = env.QUERY_FEATURE_ENABLED === "1";
|
|
if (globallyEnabled) {
|
|
return true;
|
|
}
|
|
|
|
// 2. Admins always have access
|
|
if (isAdmin || isImpersonating) {
|
|
return true;
|
|
}
|
|
|
|
// 3. Check if org/global feature flag is on
|
|
const org = await prisma.organization.findFirst({
|
|
where: {
|
|
slug: organizationSlug,
|
|
members: { some: { userId } },
|
|
},
|
|
select: {
|
|
featureFlags: true,
|
|
},
|
|
});
|
|
|
|
const flag = makeFlag();
|
|
const flagResult = await flag({
|
|
key: FEATURE_FLAG.hasQueryAccess,
|
|
defaultValue: false,
|
|
overrides: (org?.featureFlags as Record<string, unknown>) ?? {},
|
|
});
|
|
if (flagResult) {
|
|
return true;
|
|
}
|
|
|
|
// 4. Not enabled anywhere
|
|
return false;
|
|
}
|