Skip to content
Draft
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 js/packages/ui/src/api/lineagecheck.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import type { CllInput } from "./cll";
// ============================================================================

export interface LineageDiffViewOptions {
view_mode?: "changed_models" | "all";
view_mode?: "changed_models" | "all" | "body_changes";
node_ids?: string[];
packages?: string[];
select?: string;
Expand Down
2 changes: 1 addition & 1 deletion js/packages/ui/src/api/schemacheck.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export interface SchemaDiffViewParams {
node_id?: string | string[];
select?: string;
exclude?: string;
view_mode?: "all" | "changed_models";
view_mode?: "all" | "changed_models" | "body_changes";
packages?: string[];
}

Expand Down
2 changes: 1 addition & 1 deletion js/packages/ui/src/api/select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export interface SelectInput {
select?: string;
exclude?: string;
packages?: string[];
view_mode?: "all" | "changed_models";
view_mode?: "all" | "changed_models" | "body_changes";
}

export interface SelectOutput {
Expand Down
8 changes: 4 additions & 4 deletions js/packages/ui/src/api/types/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@ export interface SchemaDiffParams {
exclude?: string;
/** Package names to include */
packages?: string[];
/** View mode - show all models or only changed ones */
view_mode?: "all" | "changed_models";
/** View mode - 'all', 'changed_models', or 'body_changes' (SQL body/macro/contract only) */
view_mode?: "all" | "changed_models" | "body_changes";
}

/**
Expand All @@ -134,8 +134,8 @@ export interface LineageDiffParams {
exclude?: string;
/** Package names to include */
packages?: string[];
/** View mode - show all models or only changed ones */
view_mode?: "all" | "changed_models";
/** View mode - 'all', 'changed_models', or 'body_changes' (SQL body/macro/contract only) */
view_mode?: "all" | "changed_models" | "body_changes";
}

// ============================================================================
Expand Down
2 changes: 1 addition & 1 deletion js/packages/ui/src/components/check/LineageDiffView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { LineageView, type LineageViewRef } from "../lineage/LineageView";
* View options for lineage diff checks
*/
export interface LineageDiffViewOptions {
view_mode?: "changed_models" | "all";
view_mode?: "changed_models" | "all" | "body_changes";
node_ids?: string[];
select?: string;
exclude?: string;
Expand Down
2 changes: 1 addition & 1 deletion js/packages/ui/src/components/check/SchemaDiffView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export interface SchemaDiffParams {
node_id?: string | string[];
select?: string;
exclude?: string;
view_mode?: "all" | "changed_models";
view_mode?: "all" | "changed_models" | "body_changes";
packages?: string[];
}

Expand Down
9 changes: 6 additions & 3 deletions js/packages/ui/src/components/lineage/LineageView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export interface LineageViewProps {
* View options for lineage diff visualization
*/
viewOptions?: {
view_mode?: "changed_models" | "all";
view_mode?: "changed_models" | "all" | "body_changes";
node_ids?: string[];
select?: string;
exclude?: string;
Expand Down Expand Up @@ -201,8 +201,11 @@ export const LineageView = forwardRef<LineageViewRef, LineageViewProps>(
if (viewOptions?.node_ids && viewOptions.node_ids.length > 0) {
// Explicit node selection
selectedNodeIds = viewOptions.node_ids;
} else if (viewOptions?.view_mode === "changed_models") {
// Only changed models
} else if (
viewOptions?.view_mode === "changed_models" ||
viewOptions?.view_mode === "body_changes"
) {
// Changed models or body changes (filtering done server-side via selector)
selectedNodeIds = lineageGraph.modifiedSet;
}

Expand Down
17 changes: 15 additions & 2 deletions js/packages/ui/src/components/lineage/topbar/LineageViewTopBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,12 @@ const ViewModeSelectMenu = ({
const open = Boolean(anchorEl);

const viewMode = viewOptions.view_mode ?? "changed_models";
const label = viewMode === "changed_models" ? "Changed Models" : "All";
const label =
viewMode === "body_changes"
? "Body Changes"
: viewMode === "changed_models"
? "Changed Models"
: "All";

const handleClick = (event: MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget);
Expand Down Expand Up @@ -256,6 +261,14 @@ const ViewModeSelectMenu = ({
sx={{ m: 0 }}
/>
</MenuItem>
<MenuItem onClick={() => handleSelect("body_changes")}>
<FormControlLabel
value="body_changes"
control={<Radio size="small" sx={{ py: 0 }} />}
label="Body Changes"
sx={{ m: 0 }}
/>
</MenuItem>
<MenuItem onClick={() => handleSelect("all")}>
<FormControlLabel
value="all"
Expand Down Expand Up @@ -559,7 +572,7 @@ const DefaultSetupConnectionPopover = ({
* LineageViewTopBar Component
*
* Top toolbar for the lineage view providing:
* - View mode selection (Changed Models vs All)
* - View mode selection (Changed Models, Body Changes, All)
* - Package filtering
* - Node selector filters (Select, Exclude)
* - Actions menu for diff operations and checklist additions
Expand Down
45 changes: 45 additions & 0 deletions js/src/components/lineage/__tests__/LineageViewTopBar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,20 @@ describe("LineageViewTopBar", () => {
expect(modeButton).toBeDefined();
});

it("shows Body Changes when view mode is body_changes", () => {
mockUseLineageViewContextSafe.mockReturnValue(
createMockLineageViewContext({
viewOptions: { view_mode: "body_changes" },
}),
);

render(<LineageViewTopBar />);

expect(
screen.getByRole("button", { name: /Body Changes/i }),
).toBeInTheDocument();
});

it("opens mode menu when clicked", async () => {
render(<LineageViewTopBar />);

Expand All @@ -395,12 +409,43 @@ describe("LineageViewTopBar", () => {
expect(
screen.getByRole("radio", { name: /Changed Models/i }),
).toBeInTheDocument();
expect(
screen.getByRole("radio", { name: /Body Changes/i }),
).toBeInTheDocument();
expect(
screen.getByRole("radio", { name: /^All$/i }),
).toBeInTheDocument();
});
});

it("calls onViewOptionsChanged when mode is changed to body_changes", async () => {
const mockOnViewOptionsChanged = vi.fn();
mockUseLineageViewContextSafe.mockReturnValue(
createMockLineageViewContext({
viewOptions: { view_mode: "changed_models" },
onViewOptionsChanged: mockOnViewOptionsChanged,
}),
);

render(<LineageViewTopBar />);

const modeButton = screen.getByRole("button", {
name: /Changed Models/i,
});
fireEvent.click(modeButton);

await waitFor(() => {
const bodyChangesMenuItem = screen.getByRole("menuitem", {
name: /Body Changes/i,
});
fireEvent.click(bodyChangesMenuItem);
});

expect(mockOnViewOptionsChanged).toHaveBeenCalledWith(
expect.objectContaining({ view_mode: "body_changes" }),
);
});

it("calls onViewOptionsChanged when mode is changed to all", async () => {
const mockOnViewOptionsChanged = vi.fn();
mockUseLineageViewContextSafe.mockReturnValue(
Expand Down
2 changes: 1 addition & 1 deletion recce/adapter/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def select_nodes(
select: Optional[str] = None,
exclude: Optional[str] = None,
packages: Optional[list[str]] = None,
view_mode: Optional[Literal["all", "changed_models"]] = None,
view_mode: Optional[Literal["all", "changed_models", "body_changes"]] = None,
) -> Set[str]:
raise NotImplementedError()

Expand Down
10 changes: 8 additions & 2 deletions recce/adapter/dbt_adapter/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1857,7 +1857,7 @@ def select_nodes(
select: Optional[str] = None,
exclude: Optional[str] = None,
packages: Optional[list[str]] = None,
view_mode: Optional[Literal["all", "changed_models"]] = None,
view_mode: Optional[Literal["all", "changed_models", "body_changes"]] = None,
) -> Set[str]:
import dbt.compilation
from dbt.compilation import Compiler
Expand Down Expand Up @@ -1891,8 +1891,14 @@ def _parse_difference(include, exclude):
if packages is not None:
package_spec = SelectionUnion([_parse_difference([f"package:{p}"], None) for p in packages])
specs.append(package_spec)
if view_mode and view_mode == "changed_models":
if view_mode == "changed_models":
specs.append(_parse_difference(["1+state:modified+"], None))
elif view_mode == "body_changes":
specs.append(
_parse_difference(
["1+state:modified.body+", "1+state:modified.macros+", "1+state:modified.contract+"], None
)
)
spec = SelectionIntersection(specs)

manifest = Manifest()
Expand Down
8 changes: 4 additions & 4 deletions recce/mcp_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,9 +241,9 @@ async def list_tools() -> List[Tool]:
},
"view_mode": {
"type": "string",
"enum": ["changed_models", "all"],
"enum": ["changed_models", "all", "body_changes"],
"default": "changed_models",
"description": "View mode: 'changed_models' for only changed models (default), 'all' for all models",
"description": "View mode: 'changed_models' for only changed models (default), 'all' for all models, 'body_changes' for SQL body/macro/contract changes only",
},
},
},
Expand Down Expand Up @@ -362,8 +362,8 @@ async def list_tools() -> List[Tool]:
},
"view_mode": {
"type": "string",
"enum": ["all", "changed_models"],
"description": "View mode: 'all' for all models, 'changed_models' for only changed models (optional)",
"enum": ["all", "changed_models", "body_changes"],
"description": "View mode: 'all' for all models, 'changed_models' for only changed models (optional), 'body_changes' for SQL body/macro/contract changes only",
},
},
},
Expand Down
2 changes: 1 addition & 1 deletion recce/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -663,7 +663,7 @@ class SelectNodesInput(BaseModel):
select: Optional[str] = None
exclude: Optional[str] = None
packages: Optional[list[str]] = None
view_mode: Optional[Literal["all", "changed_models"]] = None
view_mode: Optional[Literal["all", "changed_models", "body_changes"]] = None


class SelectNodesOutput(BaseModel):
Expand Down
2 changes: 1 addition & 1 deletion recce/tasks/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def get_node_ids_by_selector(
select: Optional[str] = None,
exclude: Optional[str] = None,
packages: Optional[list[str]] = None,
view_mode: Optional[Literal["all", "changed_models"]] = None,
view_mode: Optional[Literal["all", "changed_models", "body_changes"]] = None,
) -> List[str]:
nodes = default_context().adapter.select_nodes(
select=select, exclude=exclude, packages=packages, view_mode=view_mode
Expand Down
2 changes: 1 addition & 1 deletion recce/tasks/lineage.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class LineageDiffParams(BaseModel):
select: Optional[str] = None
exclude: Optional[str] = None
packages: Optional[list[str]] = None
view_mode: Optional[Literal["all", "changed_models"]] = None
view_mode: Optional[Literal["all", "changed_models", "body_changes"]] = None


class LineageDiffCheckValidator(CheckValidator):
Expand Down
2 changes: 1 addition & 1 deletion recce/tasks/rowcount.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ class RowCountDiffParams(BaseModel):
select: Optional[str] = None
exclude: Optional[str] = None
packages: Optional[list[str]] = None
view_mode: Optional[Literal["all", "changed_models"]] = None
view_mode: Optional[Literal["all", "changed_models", "body_changes"]] = None


class RowCountDiffTask(Task, QueryMixin):
Expand Down
2 changes: 1 addition & 1 deletion recce/tasks/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class SchemaDiffParams(BaseModel):
select: Optional[str] = None
exclude: Optional[str] = None
packages: Optional[list[str]] = None
view_mode: Optional[Literal["all", "changed_models"]] = None
view_mode: Optional[Literal["all", "changed_models", "body_changes"]] = None


class SchemaDiffCheckValidator(CheckValidator):
Expand Down
4 changes: 4 additions & 0 deletions tests/adapter/dbt_adapter/test_selector.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,10 @@ def test_select_with_pacakage_mode_include_exclude(dbt_test_helper):
node_ids = adapter.select_nodes(view_mode="changed_models")
assert len(node_ids) == 3

# body_changes: only body/macros/contract changes (same result here since the change is a body change)
node_ids = adapter.select_nodes(view_mode="body_changes")
assert len(node_ids) == 3

node_ids = adapter.select_nodes(view_mode="changed_models", packages=["other_package"])
assert len(node_ids) == 1

Expand Down
2 changes: 1 addition & 1 deletion tests/tasks/test_lineage.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def validate(params: dict):
}
)

# view_mode should be 'all' or 'changed_models'
# view_mode should be 'all', 'changed_models', or 'body_changes'
validate(
{
"view_mode": None,
Expand Down
2 changes: 1 addition & 1 deletion tests/tasks/test_row_count.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def validate(params: dict):
}
)

# view_mode should be 'all' or 'changed_models'
# view_mode should be 'all', 'changed_models', or 'body_changes'
validate(
{
"view_mode": None,
Expand Down
2 changes: 1 addition & 1 deletion tests/tasks/test_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def validate(params: dict):
}
)

# view_mode should be 'all' or 'changed_models'
# view_mode should be 'all', 'changed_models', or 'body_changes'
validate(
{
"view_mode": None,
Expand Down
Loading