Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion studio/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,4 @@ We use [Connect](https://connect.build/) to unify the communication between all

## Docker Info

We want runtime envs for docker for each on prem customer. Therefore we have two files to achieve this. One is .env.docker that uses a placeholder env name and an entrypoint.sh script that replaces all placeholder env name with the correct one at runtime in the .next folder. This also requires us to SSR the studio.
We want runtime envs for docker for each on prem customer. Therefore we have two files to achieve this. One is .env.docker that uses a placeholder env name and an entrypoint.sh script that replaces all placeholder env name with the correct one at runtime in the .next folder. This also requires us to SSR the studio.
32 changes: 17 additions & 15 deletions studio/next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -52,39 +52,41 @@ if (isSentryEnabled) {

const lightweightCspHeader = `
style-src 'report-sample' 'self' 'unsafe-inline' data: ${
isPreview || isProduction ? 'https://vercel.live' : ''
isPreview || isProduction ? "https://vercel.live" : ""
};
object-src 'none';
base-uri 'self';
font-src 'self' data:${
isPreview || isProduction ? ' https://vercel.live https://assets.vercel.com' : ''
isPreview || isProduction
? " https://vercel.live https://assets.vercel.com"
: ""
};
frame-src 'self' https://js.stripe.com https://hooks.stripe.com https://www.googletagmanager.com${
isPreview || isProduction ? ' https://vercel.live https://vercel.com' : ''
isPreview || isProduction ? " https://vercel.live https://vercel.com" : ""
};
img-src 'self' https://wundergraph.com ${
isPreview || isProduction
? ' https://vercel.live/ https://vercel.com *.pusher.com data: blob:'
: ''
? " https://vercel.live/ https://vercel.com *.pusher.com data: blob:"
: ""
} *.ads.linkedin.com *.google.com;
script-src 'report-sample' 'self' 'unsafe-inline' ${
allowUnsafeEval ? "'unsafe-eval'" : ''
allowUnsafeEval ? "'unsafe-eval'" : ""
} https://*.wundergraph.com https://js.stripe.com https://maps.googleapis.com https://plausible.io https://wundergraph.com https://static.reo.dev${
isPreview || isProduction ? ' https://vercel.live https://vercel.com' : ''
isPreview || isProduction ? " https://vercel.live https://vercel.com" : ""
} ${
isProduction
? [
'https://www.googletagmanager.com',
'https://snap.licdn.com',
'https://cmp.osano.com',
'https://googleads.g.doubleclick.net',
'https://*.clarity.ms',
].join(' ')
: ''
"https://www.googletagmanager.com",
"https://snap.licdn.com",
"https://cmp.osano.com",
"https://googleads.g.doubleclick.net",
"https://*.clarity.ms",
].join(" ")
: ""
};
manifest-src 'self';
media-src 'self';
worker-src 'self'${isSentryFeatureReplayEnabled ? ' blob:' : ''};
worker-src 'self'${isSentryFeatureReplayEnabled ? " blob:" : ""};
`;

/**
Expand Down
18 changes: 12 additions & 6 deletions studio/sentry.client.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,21 @@ init({
* This is independent of `sessionSampleRate`.
* 1.0 will record all sessions and 0 will record none.
*/
replaysOnErrorSampleRate: isSentryFeatureReplayEnabled ? parseFloat(
process.env.NEXT_PUBLIC_SENTRY_CLIENT_REPLAYS_ON_ERROR_SAMPLE_RATE || "0",
) : 0,
replaysOnErrorSampleRate: isSentryFeatureReplayEnabled
? parseFloat(
process.env.NEXT_PUBLIC_SENTRY_CLIENT_REPLAYS_ON_ERROR_SAMPLE_RATE ||
"0",
)
: 0,
/**
* The sample rate for session-long replays.
* 1.0 will record all sessions and 0 will record none.
*/
replaysSessionSampleRate: isSentryFeatureReplayEnabled ? parseFloat(
process.env.NEXT_PUBLIC_SENTRY_CLIENT_REPLAYS_SESSION_SAMPLE_RATE || "0",
) : 0,
replaysSessionSampleRate: isSentryFeatureReplayEnabled
? parseFloat(
process.env.NEXT_PUBLIC_SENTRY_CLIENT_REPLAYS_SESSION_SAMPLE_RATE ||
"0",
)
: 0,
integrations,
});
4 changes: 3 additions & 1 deletion studio/sentry.edge.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,

// Adjust this value in production, or use tracesSampler for greater control
tracesSampleRate: parseFloat(process.env.NEXT_PUBLIC_SENTRY_EDGE_SAMPLE_RATE || "0"),
tracesSampleRate: parseFloat(
process.env.NEXT_PUBLIC_SENTRY_EDGE_SAMPLE_RATE || "0",
),

// Setting this option to true will print useful information to the console while you're setting up Sentry.
debug: process.env.SENTRY_DEBUG === "true",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import { compressToEncodedURIComponent } from "lz-string";
import { describe, expect, test, vi } from "vitest";
import { PlaygroundUrlState, TabState } from "../components/playground/types";
import { PLAYGROUND_STATE_QUERY_PARAM } from "../lib/constants";
import { decompressState, extractStateFromUrl } from "../lib/playground-url-state-decoding";
import {
decompressState,
extractStateFromUrl,
} from "../lib/playground-url-state-decoding";
import { buildStateToShare } from "../lib/playground-url-state-encoding";

describe("buildStateToShare", () => {
Expand Down Expand Up @@ -62,7 +65,9 @@ describe("buildStateToShare", () => {

describe("createCompressedStateUrl", () => {
test("returns valid URL with compressed query param", async () => {
const { createCompressedStateUrl } = await import("../lib/playground-url-state-encoding");
const { createCompressedStateUrl } = await import(
"../lib/playground-url-state-encoding"
);

const state = { operation: "query { test }" };
const BASE_URL = "https://my.studio.dev";
Expand All @@ -78,21 +83,24 @@ describe("createCompressedStateUrl", () => {
});

test("throws error if compression fails", async () => {
// ensure a fresh module state
// ensure a fresh module state
vi.resetModules();

// Mock lz-string's compression to simulate a failure
// Note: doMock must be followed by re-import
vi.doMock("lz-string", async () => {
const actual = await vi.importActual<typeof import("lz-string")>("lz-string");
const actual =
await vi.importActual<typeof import("lz-string")>("lz-string");
return {
...actual,
compressToEncodedURIComponent: () => "",
};
});

// Re-import the module after mocking to ensure mock is applied
const { createCompressedStateUrl } = await import("../lib/playground-url-state-encoding");
const { createCompressedStateUrl } = await import(
"../lib/playground-url-state-encoding"
);

expect(() => {
createCompressedStateUrl({ operation: "query { fail }" });
Expand All @@ -107,7 +115,9 @@ describe("decompressState", () => {
variables: '{ "foo": "bar" }',
};

const compressed = compressToEncodedURIComponent(JSON.stringify(originalState));
const compressed = compressToEncodedURIComponent(
JSON.stringify(originalState),
);
const result = decompressState(compressed);

expect(result).toEqual(originalState);
Expand All @@ -116,18 +126,21 @@ describe("decompressState", () => {
test("throws error if decompressFromEncodedURIComponent fails", async () => {
// ensure a fresh module state
vi.resetModules();

vi.doMock("lz-string", async () => {
const actual = await vi.importActual<typeof import("lz-string")>("lz-string");
const actual =
await vi.importActual<typeof import("lz-string")>("lz-string");
return {
...actual,
decompressFromEncodedURIComponent: () => null, // simulate failure
};
});

// re-import after mock is applied
const { decompressState } = await import("../lib/playground-url-state-decoding");

const { decompressState } = await import(
"../lib/playground-url-state-decoding"
);

expect(() => {
decompressState("invalid-compressed-string");
}).toThrow("Failed to decompress playground state");
Expand All @@ -136,15 +149,17 @@ describe("decompressState", () => {
test("throws error if schema is invalid", async () => {
// ensure a fresh module state
vi.resetModules();

// missing required "operation" field
const badState = { foo: "bar" };
const compressed = compressToEncodedURIComponent(JSON.stringify(badState));

// re-import decompressState after module reset
// Note: lz-string doesn't need to be mocked here
const { decompressState } = await import("../lib/playground-url-state-decoding");

const { decompressState } = await import(
"../lib/playground-url-state-decoding"
);

expect(() => {
decompressState(compressed);
}).toThrow("Failed to decompress playground state");
Expand Down Expand Up @@ -173,4 +188,4 @@ describe("extractStateFromUrl", () => {
const result = extractStateFromUrl();
expect(result).toBeNull();
});
});
});
15 changes: 11 additions & 4 deletions studio/src/__tests__/schema-helpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,18 @@ test("return the correct types with deprecated fields or args", () => {
expect(result).not.toBeNull();

const parsedTypes = getParsedTypes(result!.doc);
const [totalDeprecatedNodesCount, deprecated] = getDeprecatedTypes(parsedTypes);
const [totalDeprecatedNodesCount, deprecated] =
getDeprecatedTypes(parsedTypes);

expect(totalDeprecatedNodesCount).toEqual(2);
expect(deprecated.length).toEqual(2);
expect(deprecated[0].fields?.length).toEqual(1);
expect(deprecated[0].fields?.[0]?.name).toEqual("teammates");
expect(deprecated[1].fields?.length).toEqual(1);
expect(deprecated[1].fields?.[0]?.name).toEqual("fullName");
expect(deprecated[1].fields?.[0]?.deprecationReason).toEqual("Please use first and last name instead");
expect(deprecated[1].fields?.[0]?.deprecationReason).toEqual(
"Please use first and last name instead",
);
});

test("that authentication types are read correctly", async () => {
Expand All @@ -74,7 +77,8 @@ test("that authentication types are read correctly", async () => {
expect(result).not.toBeNull();

const parsedTypes = getParsedTypes(result!.doc);
const [totalAuthenticatedNodesCount, authenticatedTypes] = getAuthenticatedTypes(parsedTypes);
const [totalAuthenticatedNodesCount, authenticatedTypes] =
getAuthenticatedTypes(parsedTypes);

expect(totalAuthenticatedNodesCount).toEqual(4);
expect(authenticatedTypes.length).toEqual(3);
Expand All @@ -84,7 +88,10 @@ test("that authentication types are read correctly", async () => {
expect(authenticatedTypes[2].fields?.length).toEqual(2);
expect(authenticatedTypes[2].fields?.[0]?.name).toEqual("role");
expect(authenticatedTypes[2].fields?.[1]?.name).toEqual("email");
expect(authenticatedTypes[2].fields?.[1]?.requiresScopes).toStrictEqual([["read:profile", "read:email"], ["read:all"]]);
expect(authenticatedTypes[2].fields?.[1]?.requiresScopes).toStrictEqual([
["read:profile", "read:email"],
["read:all"],
]);
});

test("returns correct type counts", () => {
Expand Down
4 changes: 2 additions & 2 deletions studio/src/components/analytics/charts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ const labelFormatter = (label: number, utc?: boolean) => {
return utc
? new Date(label).toUTCString()
: label
? formatDateTime(label)
: label;
? formatDateTime(label)
: label;
};

export const valueFormatter = (tick: number) =>
Expand Down
2 changes: 1 addition & 1 deletion studio/src/components/analytics/delta-badge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const deltaBadgeVariants = cva(
defaultVariants: {
type: "neutral",
},
}
},
);

export interface DeltaBadgeProps
Expand Down
4 changes: 3 additions & 1 deletion studio/src/components/analytics/filters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ export const AnalyticsFilters: React.FC<AnalyticsFiltersProps> = (props) => {

return (
<>
{filters.length > 0 && <DataTablePrimaryFilterMenu filters={filters} className={className} />}
{filters.length > 0 && (
<DataTablePrimaryFilterMenu filters={filters} className={className} />
)}
</>
);
};
Expand Down
4 changes: 3 additions & 1 deletion studio/src/components/analytics/toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ export const AnalyticsToolbar: React.FC<{
children?: React.ReactNode;
}> = (props) => {
const router = useRouter();
const { namespace: { name: namespace } } = useWorkspace();
const {
namespace: { name: namespace },
} = useWorkspace();
const organizationSlug = useCurrentOrganization()?.slug;

const query: ParsedUrlQueryInput = {
Expand Down
Loading
Loading