import { View, Text, StyleSheet, ScrollView } from "react-native";
import { Query, useQueryClient } from "@tanstack/react-query";
import { useSafeAreaInsets } from "@react-buoy/shared-ui";
import Explorer from "./query-browser/Explorer";
import QueryDetails from "./query-browser/QueryDetails";
import ActionButton from "./query-browser/ActionButton";
import { getQueryStatusLabel } from "../utils/getQueryStatusLabel";
import { useActionButtons } from "../hooks/useActionButtons";
import { macOSColors } from "@react-buoy/shared-ui";
import { DataViewer } from "@react-buoy/shared-ui/dataViewer";
interface ActionButtonConfig {
label: string;
bgColorClass:
| "btnRefetch"
| "btnTriggerLoading"
| "btnTriggerLoadiError"
| "btnRemove";
textColorClass:
| "btnRefetch"
| "btnTriggerLoading"
| "btnTriggerLoadiError"
| "btnRemove";
disabled: boolean;
onPress: () => void;
}
interface DataEditorModeProps {
selectedQuery: Query;
isFloatingMode: boolean;
disableInternalFooter?: boolean;
/** Version number that increments when query state changes, used to force re-renders */
queryVersion?: number;
}
/**
* Primary data editing surface displayed inside the React Query modal. Couples the editable
* explorer, read-only insight panels, and action footer for the selected query.
*/
export function DataEditorMode({
selectedQuery,
isFloatingMode,
disableInternalFooter = false,
queryVersion,
}: DataEditorModeProps) {
const insets = useSafeAreaInsets({ minBottom: 16 });
const queryClient = useQueryClient();
const actionButtons = useActionButtons(selectedQuery, queryClient, queryVersion);
return (
<>
{/* Data Explorer Section - Moved to top for immediate data editing */}
{/* Query Details Section */}
{/* Query Explorer Section - Non-editable viewer */}
Query Explorer
{/* Action Footer with Safe Area (internal, optional) */}
{!disableInternalFooter && (
{actionButtons.map((action: ActionButtonConfig, index: number) => (
))}
)}
>
);
}
// External footer component for sticky modal footer usage
/**
* Standalone footer variant that can be composed into sticky modal layouts while reusing the
* standard action button arrangement.
*/
export function DataEditorActionsFooter({
selectedQuery,
isFloatingMode,
queryVersion,
}: {
selectedQuery: Query;
isFloatingMode: boolean;
/** Version number that increments when query state changes, used to force re-renders */
queryVersion?: number;
}) {
const insets = useSafeAreaInsets({ minBottom: 16 });
const queryClient = useQueryClient();
const actionButtons = useActionButtons(selectedQuery, queryClient, queryVersion);
return (
{actionButtons.map((action: ActionButtonConfig, index: number) => (
))}
);
}
function DataExplorer({
visible,
selectedQuery,
queryVersion = 0,
}: {
visible: boolean;
selectedQuery: Query;
queryVersion?: number;
}) {
if (!visible) return null;
return (
Data Editor
);
}
function DataEmptyState({
visible,
selectedQuery,
}: {
visible: boolean;
selectedQuery: Query;
}) {
if (!visible) return null;
const getEmptyStateContent = () => {
// Check if query is disabled first
if (selectedQuery.isDisabled()) {
return {
title: "Query Disabled",
description:
"This query is disabled and won't automatically fetch. Enable the query or manually trigger a fetch to load data.",
};
}
if (
selectedQuery.state.status === "pending" ||
getQueryStatusLabel(selectedQuery) === "fetching"
) {
return {
title:
selectedQuery.state.status === "pending"
? "Loading..."
: "Refetching...",
description: "Please wait while the query is being executed.",
};
}
if (selectedQuery.state.status === "error") {
return {
title: "Query Error",
description:
selectedQuery.state.error?.message ||
"An error occurred while fetching data.",
};
}
return {
title: "No Data Available",
description:
"This query has no data to edit. Try refetching the query first.",
};
};
const { title, description } = getEmptyStateContent();
return (
{title}
{description}
);
}
const styles = StyleSheet.create({
// Explorer section
explorerScrollContainer: {
flex: 1,
},
explorerScrollContent: {
paddingBottom: 16,
paddingHorizontal: 8,
flexGrow: 1,
},
// Section layout matching QueryInformation
section: {
marginBottom: 16,
},
// Empty states matching main dev tools
emptyState: {
flex: 1,
justifyContent: "center",
alignItems: "center",
padding: 32,
},
emptyTitle: {
color: macOSColors.text.primary,
fontSize: 18,
fontWeight: "600",
marginBottom: 8,
textAlign: "center",
},
emptyDescription: {
color: macOSColors.text.secondary,
fontSize: 14,
textAlign: "center",
lineHeight: 20,
maxWidth: 280,
},
// Action footer matching main dev tools exactly
actionFooter: {
borderTopWidth: 1,
borderTopColor: macOSColors.border.default,
paddingTop: 4,
paddingHorizontal: 12,
backgroundColor: macOSColors.background.base,
borderBottomLeftRadius: 14,
borderBottomRightRadius: 14,
},
actionsGrid: {
flexDirection: "row",
flexWrap: "wrap",
gap: 6, // Reduced from 8
justifyContent: "space-between",
paddingBottom: 2,
},
// Query Explorer styled container matching QueryDetails
queryExplorerContainer: {
minWidth: 200,
backgroundColor: macOSColors.background.card,
borderRadius: 6,
borderWidth: 1,
borderColor: macOSColors.semantic.info + "4D",
overflow: "hidden",
shadowColor: macOSColors.semantic.info,
shadowOffset: { width: 0, height: 0 },
shadowOpacity: 0.1,
shadowRadius: 6,
},
queryExplorerHeader: {
backgroundColor: macOSColors.semantic.infoBackground,
paddingHorizontal: 12,
paddingVertical: 10,
fontWeight: "600",
fontSize: 12,
color: macOSColors.semantic.info,
borderBottomWidth: 1,
borderBottomColor: macOSColors.semantic.info + "33",
letterSpacing: 0.5,
textTransform: "uppercase",
fontFamily: "monospace",
},
queryExplorerContent: {
padding: 8,
},
// Data section with green accent - editable/success theme
dataContainer: {
minWidth: 200,
backgroundColor: macOSColors.background.card,
borderRadius: 6,
borderWidth: 1,
borderColor: macOSColors.semantic.info + "4D",
overflow: "hidden",
shadowColor: macOSColors.semantic.info,
shadowOffset: { width: 0, height: 0 },
shadowOpacity: 0.1,
shadowRadius: 6,
marginTop: 8,
},
dataHeader: {
backgroundColor: macOSColors.semantic.infoBackground,
paddingHorizontal: 12,
paddingVertical: 10,
fontWeight: "600",
fontSize: 12,
color: macOSColors.semantic.info,
borderBottomWidth: 1,
borderBottomColor: macOSColors.semantic.info + "33",
letterSpacing: 0.5,
textTransform: "uppercase",
fontFamily: "monospace",
},
dataContent: {
padding: 8,
},
});