{s.originalFunctionName ?? defaultFunctionName}
@@ -95,9 +96,8 @@ export const StackElement: React.FC<{
}}
style={{
...location,
+ color: locationHovered ? WHITE : LIGHT_TEXT,
cursor: 'pointer',
- textDecoration: locationHovered ? 'underline' : 'none',
- textUnderlineOffset: locationHovered ? 4 : undefined,
}}
>
{formatLocation(s.originalFileName as string)}:
@@ -114,7 +114,14 @@ export const StackElement: React.FC<{
{s.originalScriptCode && s.originalScriptCode.length > 0 ? (
) : null}
diff --git a/packages/studio/src/error-overlay/remotion-overlay/Symbolicating.tsx b/packages/studio/src/error-overlay/remotion-overlay/Symbolicating.tsx
index 1c699436613..a15273e51a4 100644
--- a/packages/studio/src/error-overlay/remotion-overlay/Symbolicating.tsx
+++ b/packages/studio/src/error-overlay/remotion-overlay/Symbolicating.tsx
@@ -7,8 +7,8 @@ export const Symbolicating: React.FC = (props) => {
id="loading"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 32 32"
- width="16"
- height="16"
+ width="14"
+ height="14"
fill={WHITE}
{...props}
>
diff --git a/packages/studio/src/helpers/can-show-updates.ts b/packages/studio/src/helpers/can-show-updates.ts
new file mode 100644
index 00000000000..be2ed70bc50
--- /dev/null
+++ b/packages/studio/src/helpers/can-show-updates.ts
@@ -0,0 +1,15 @@
+import type {PreviewServerConnectionState} from './preview-server-events';
+
+export const canShowUpdates = ({
+ connectionStatus,
+ isBrowserStudio,
+ readOnlyStudio,
+}: {
+ readonly connectionStatus: PreviewServerConnectionState['type'];
+ readonly isBrowserStudio: boolean;
+ readonly readOnlyStudio: boolean;
+}) => {
+ return (
+ connectionStatus === 'connected' && !isBrowserStudio && !readOnlyStudio
+ );
+};
diff --git a/packages/studio/src/helpers/colors.ts b/packages/studio/src/helpers/colors.ts
index 59050913364..3a78e60aa1f 100644
--- a/packages/studio/src/helpers/colors.ts
+++ b/packages/studio/src/helpers/colors.ts
@@ -64,7 +64,6 @@ export const ERROR_CODE_FRAME_LINE_BACKGROUND = '#121212';
export const ERROR_LINK_COLOR = '#58a6ff';
export const INFO_BLUE = '#60a5fa';
export const SERVER_DISCONNECTED_BACKGROUND = '#e74c3c';
-export const STACK_FRAME_BORDER_BLUE = 'rgb(66, 144, 245)';
export const TIMELINE_BACKGROUND_COLOR = '#15181B';
// WHITE_ALPHA_10 composited over TIMELINE_BACKGROUND_COLOR.
export const TIMELINE_NEGATIVE_START_BACKGROUND_COLOR = '#2C2F32';
@@ -92,7 +91,6 @@ export const BORDER_BLACK_ALPHA_60 = `1px solid ${BLACK_ALPHA_60}`;
export const BORDER_WHITE_ALPHA_12 = `1px solid ${WHITE_ALPHA_12}`;
export const BORDER_WHITE_ALPHA_20 = `1px solid ${WHITE_ALPHA_20}`;
export const BORDER_INFO_BLUE = '1px solid rgba(59, 130, 246, 0.4)';
-export const BORDER_STACK_FRAME_BLUE = `1px solid ${STACK_FRAME_BORDER_BLUE}`;
export const BORDER_TIMELINE_DROP_BLUE = `1px solid ${TIMELINE_DROP_BLUE_ALPHA_75}`;
export const BORDER_TIMELINE_MARQUEE_BLUE = `1px solid ${TIMELINE_MARQUEE_BLUE_ALPHA_75}`;
export const SHADOW_BLACK = `0 0 4px ${BLACK}`;
diff --git a/packages/studio/src/state/modals.ts b/packages/studio/src/state/modals.ts
index 4f023729986..0204642e573 100644
--- a/packages/studio/src/state/modals.ts
+++ b/packages/studio/src/state/modals.ts
@@ -28,7 +28,6 @@ import type {StaticFile} from '../api/get-static-files';
import type {CompType} from '../components/NewComposition/DuplicateComposition';
import type {QuickSwitcherMode} from '../components/QuickSwitcher/NoResults';
import type {RenderType} from '../components/RenderModal/RenderModalAdvanced';
-import type {Bug, UpdateInfo} from '../components/UpdateCheck';
export type WebRenderModalState = {
type: 'web-render';
@@ -197,6 +196,8 @@ export type ModalState =
| 'studio'
| 'packages'
| 'shortcuts'
+ | 'skills'
+ | 'updates'
| 'license';
initialPublicLicenseKey: string | null;
}
@@ -206,11 +207,6 @@ export type ModalState =
type: 'render-progress';
jobId: string;
}
- | {
- type: 'update';
- info: UpdateInfo;
- knownBugs: Bug[];
- }
| {
type: 'fix-computed-value';
prop: string;
diff --git a/packages/studio/src/test/can-show-updates.test.ts b/packages/studio/src/test/can-show-updates.test.ts
new file mode 100644
index 00000000000..4c107b46fb8
--- /dev/null
+++ b/packages/studio/src/test/can-show-updates.test.ts
@@ -0,0 +1,37 @@
+import {expect, test} from 'bun:test';
+import {canShowUpdates} from '../helpers/can-show-updates';
+
+test('only shows updates in a connected, writable desktop Studio', () => {
+ expect(
+ canShowUpdates({
+ connectionStatus: 'connected',
+ isBrowserStudio: false,
+ readOnlyStudio: false,
+ }),
+ ).toBe(true);
+
+ for (const environment of [
+ {
+ connectionStatus: 'connected' as const,
+ isBrowserStudio: false,
+ readOnlyStudio: true,
+ },
+ {
+ connectionStatus: 'connected' as const,
+ isBrowserStudio: true,
+ readOnlyStudio: false,
+ },
+ {
+ connectionStatus: 'disconnected' as const,
+ isBrowserStudio: false,
+ readOnlyStudio: false,
+ },
+ {
+ connectionStatus: 'init' as const,
+ isBrowserStudio: false,
+ readOnlyStudio: false,
+ },
+ ]) {
+ expect(canShowUpdates(environment)).toBe(false);
+ }
+});
diff --git a/packages/studio/src/test/sequence-props-observer.test.tsx b/packages/studio/src/test/sequence-props-observer.test.tsx
new file mode 100644
index 00000000000..4d9369b6e4f
--- /dev/null
+++ b/packages/studio/src/test/sequence-props-observer.test.tsx
@@ -0,0 +1,142 @@
+import {afterEach, expect, test} from 'bun:test';
+import {cleanup, render} from '@testing-library/react';
+import {Internals, type SequencePropsSubscriptionKey} from 'remotion';
+import {ExpandedTracksSetterContext} from '../components/ExpandedTracksProvider';
+import {subscribeToSequencePropsRefresh} from '../components/Timeline/sequence-props-subscription-store';
+import {SequencePropsObserver} from '../components/Timeline/SequencePropsObserver';
+import {FastRefreshContext} from '../fast-refresh-context';
+import {StudioServerConnectionCtx} from '../helpers/client-id';
+import {queueSequenceNodePathMutation} from '../helpers/sequence-node-path-mutations';
+
+afterEach(cleanup);
+
+test('refreshes prop statuses for inserted and in-place updated nodes', () => {
+ const absolutePath = '/project/src/BarChart.tsx';
+ const originalPath = ['body', 0] as const;
+ const insertedPath = ['body', 1] as const;
+ const shiftedPath = ['body', 2] as const;
+ const originalNodePath: SequencePropsSubscriptionKey = {
+ absolutePath,
+ effectKeys: [],
+ nodePath: [...originalPath],
+ sequenceKeys: ['hidden', 'name'],
+ videoConfigValues: null,
+ };
+ const insertedNodePath: SequencePropsSubscriptionKey = {
+ absolutePath,
+ effectKeys: [],
+ nodePath: [...insertedPath],
+ sequenceKeys: ['hidden', 'name'],
+ videoConfigValues: null,
+ };
+ const refreshedOverrideIds: string[] = [];
+ const setOverrideCalls: Array<{
+ overrideId: string;
+ nodePath: SequencePropsSubscriptionKey | null;
+ }> = [];
+ const statusRemappingCalls: unknown[] = [];
+ const migrationCalls: unknown[] = [];
+ const unsubscribeOriginalRefresh = subscribeToSequencePropsRefresh(
+ 'original-override',
+ () => refreshedOverrideIds.push('original-override'),
+ );
+ const unsubscribeInsertedRefresh = subscribeToSequencePropsRefresh(
+ 'inserted-override',
+ () => refreshedOverrideIds.push('inserted-override'),
+ );
+
+ queueSequenceNodePathMutation({
+ mutationId: 'inserted-runtime-path-test',
+ files: [
+ {
+ absolutePath,
+ remappings: [
+ {oldNodePath: [...originalPath], newNodePath: [...originalPath]},
+ {oldNodePath: [...insertedPath], newNodePath: [...shiftedPath]},
+ {oldNodePath: null, newNodePath: [...insertedPath]},
+ ],
+ },
+ ],
+ });
+
+ try {
+ render(
+
() => undefined,
+ } as never
+ }
+ >
+ undefined,
+ }}
+ >
+ undefined,
+ toggleTrack: () => undefined,
+ migrateExpandedTracksForSubscriptionKey: (
+ oldKey: SequencePropsSubscriptionKey,
+ newKey: SequencePropsSubscriptionKey,
+ ) => migrationCalls.push([oldKey, newKey]),
+ } as never
+ }
+ >
+
+
+ setOverrideCalls.push({overrideId, nodePath}),
+ }}
+ >
+
+
+ statusRemappingCalls.push(remappings),
+ setPropStatuses: () => undefined,
+ } as never
+ }
+ >
+
+
+
+
+
+
+
+ ,
+ );
+
+ expect(refreshedOverrideIds).toEqual([
+ 'original-override',
+ 'inserted-override',
+ ]);
+ expect(setOverrideCalls).toEqual([
+ {overrideId: 'original-override', nodePath: originalNodePath},
+ {overrideId: 'inserted-override', nodePath: insertedNodePath},
+ ]);
+ expect(statusRemappingCalls).toHaveLength(1);
+ expect(migrationCalls).toHaveLength(2);
+ } finally {
+ unsubscribeOriginalRefresh();
+ unsubscribeInsertedRefresh();
+ }
+});
diff --git a/turbo.json b/turbo.json
index 3fd64fc36a2..0098b822229 100644
--- a/turbo.json
+++ b/turbo.json
@@ -120,10 +120,6 @@
"NODE_OPTIONS",
"REMOTION_DOCS_LOW_MEMORY_BUILD",
"TWOSLASH_RECYCLE_LIMIT_BYTES",
- "TWOSLASH_SHARED_CACHE_DIR",
- "TWOSLASH_SHARED_CACHE_GC_INTERVAL_MS",
- "TWOSLASH_SHARED_CACHE_MAX_AGE_MS",
- "TWOSLASH_SHARED_CACHE_MAX_BYTES",
"TWOSLASH_STALL_TIMEOUT_MS",
"TWOSLASH_WORKER_COUNT",
"VERCEL"