Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Telemetry for preset check recommendation #583

Merged
merged 2 commits into from
Jan 16, 2025
Merged
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
120 changes: 83 additions & 37 deletions js/src/components/lineage/PresetCheckRecommendation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { submitRunFromCheck } from "@/lib/api/runs";
import { useRecceActionContext } from "@/lib/hooks/RecceActionContext";
import { sessionStorageKeys } from "@/lib/api/sessionStorageKeys";
import { useRecceServerFlag } from "@/lib/hooks/useRecceServerFlag";
import { trackRecommendCheck } from "@/lib/api/track";

const usePresetCheckRecommendation = () => {
const queryChecks = useQuery({
Expand Down Expand Up @@ -98,17 +99,18 @@ export const PresetCheckRecommendation = () => {
const [affectedModels, setAffectedModels] = useState<string>();
const [performedRecommend, setPerformedRecommend] = useState<boolean>(false);
const [ignoreRecommend, setIgnoreRecommend] = useState<boolean>(false);
const [recommendRefresh, setRecommendRefresh] = useState<boolean>(false);
const [recommendRerun, setRecommendRerun] = useState<boolean>(false);
const { isOpen, onOpen, onClose } = useDisclosure();
const recommendationKey = sessionStorageKeys.recommendationIgnored;
const recommendIgnoreKey = sessionStorageKeys.recommendationIgnored;
const recommendShowKey = sessionStorageKeys.recommendationShowed;
const prevRefreshKey = sessionStorageKeys.prevRefreshTimeStamp;

useEffect(() => {
const ignored = sessionStorage.getItem(recommendationKey);
const ignored = sessionStorage.getItem(recommendIgnoreKey);
if (ignored) {
setIgnoreRecommend(true);
}
}, [recommendationKey]);
}, [recommendIgnoreKey]);

useEffect(() => {
if (!recommendedCheck || !selectedNodes) {
Expand All @@ -120,59 +122,49 @@ export const PresetCheckRecommendation = () => {
recommendedCheck.last_run?.run_at
).getTime();

let currEnvTimeStamp = 0;
let baseEnvTimeStamp = 0;
const dbtInfo = envInfo?.dbt;
if (dbtInfo?.current?.generated_at) {
currEnvTimeStamp = new Date(dbtInfo.current?.generated_at).getTime();
}
if (dbtInfo?.base?.generated_at) {
baseEnvTimeStamp = new Date(dbtInfo?.base?.generated_at).getTime();
}
const currEnvTimeStamp = dbtInfo?.current?.generated_at
? new Date(dbtInfo.current.generated_at).getTime()
: 0;
const baseEnvTimeStamp = dbtInfo?.base?.generated_at
? new Date(dbtInfo.base.generated_at).getTime()
: 0;
const envTimeStamp = Math.max(currEnvTimeStamp, baseEnvTimeStamp);

if (runTimeStamp >= envTimeStamp) {
setPerformedRecommend(true);
return;
}
setPerformedRecommend(false);
setRecommendRerun(true);

// Check if the env has been refreshed
const prevEnvTimeStamp = sessionStorage.getItem(prevRefreshKey);
if (
prevEnvTimeStamp === null ||
parseInt(prevEnvTimeStamp) !== envTimeStamp
) {
sessionStorage.setItem(prevRefreshKey, envTimeStamp.toString());
sessionStorage.removeItem(sessionStorageKeys.recommendationIgnored);
sessionStorage.removeItem(recommendIgnoreKey);
sessionStorage.removeItem(recommendShowKey);
setIgnoreRecommend(false);
}
setPerformedRecommend(false);
setRecommendRefresh(true);
}

const check = recommendedCheck;
const extractNodeNames = (nodeIds: string[]) => {
const nodes = nodeIds.map((nodeId) => lineageGraph?.nodes[nodeId]?.name);
return nodes.join(", ");
};
if (selectedNodes.length > 0 && selectedNodes.length <= 3) {
if (check.params?.node_names) {
const nodeNames = check.params?.node_names.join(", ");
setAffectedModels(`'${nodeNames}'`);
} else if (check.params?.node_ids) {
const nodes = [];
for (const nodeId of check.params?.node_ids) {
const node = lineageGraph?.nodes[nodeId];
if (node) {
nodes.push(node.name);
}
}
const nodeNames = nodes.join(", ");
const nodeNames = extractNodeNames(check.params?.node_ids);
setAffectedModels(`'${nodeNames}'`);
} else if (selectedNodes) {
const nodes = [];
for (const nodeId of selectedNodes) {
const node = lineageGraph?.nodes[nodeId];
if (node) {
nodes.push(node.name);
}
}
const nodeNames = nodes.join(", ");
const nodeNames = extractNodeNames(selectedNodes);
setAffectedModels(`'${nodeNames}'`);
}
} else if (lineageGraph?.modifiedSet?.length === selectedNodes.length) {
Expand All @@ -182,11 +174,22 @@ export const PresetCheckRecommendation = () => {
} else {
setAffectedModels(`${selectedNodes.length} models`);
}

// Track recommendation is shown the first time
if (!sessionStorage.getItem(recommendShowKey)) {
const prevEnvTimeStamp = sessionStorage.getItem(prevRefreshKey);
sessionStorage.setItem(recommendShowKey, "true");
trackRecommendCheck({
action: "recommend",
from: prevEnvTimeStamp === null ? "initial" : "rerun",
});
}
}, [
recommendedCheck,
selectedNodes,
lineageGraph,
recommendationKey,
recommendIgnoreKey,
recommendShowKey,
prevRefreshKey,
envInfo,
]);
Expand Down Expand Up @@ -216,7 +219,7 @@ export const PresetCheckRecommendation = () => {
<>
<HStack width="100%" padding="2pt 8pt" backgroundColor={"blue.50"}>
<HStack flex="1" fontSize={"10pt"} color="blue.600">
{!recommendRefresh ? (
{!recommendRerun ? (
<>
<InfoOutlineIcon />
<Text>
Expand All @@ -238,17 +241,44 @@ export const PresetCheckRecommendation = () => {
size="xs"
onClick={() => {
setIgnoreRecommend(true);
sessionStorage.setItem(recommendationKey, "true");
sessionStorage.setItem(recommendIgnoreKey, "true");
trackRecommendCheck({
action: "ignore",
from: recommendRerun ? "rerun" : "initial",
nodes: numNodes,
});
}}
>
Ignore
</Button>
<Button colorScheme="blue" size="xs" onClick={onOpen}>
<Button
colorScheme="blue"
size="xs"
onClick={() => {
onOpen();
trackRecommendCheck({
action: "perform",
from: recommendRerun ? "rerun" : "initial",
nodes: numNodes,
});
}}
>
Perform
</Button>
</HStack>
</HStack>
<Modal isOpen={isOpen} onClose={onClose} isCentered>
<Modal
isOpen={isOpen}
onClose={() => {
onClose();
trackRecommendCheck({
action: "close",
from: recommendRerun ? "rerun" : "initial",
nodes: numNodes,
});
}}
isCentered
>
<ModalOverlay />
<ModalContent>
<ModalHeader>Row Count Check</ModalHeader>
Expand All @@ -268,13 +298,29 @@ export const PresetCheckRecommendation = () => {
</Stack>
</ModalBody>
<ModalFooter gap="5px">
<Button onClick={onClose}>Cancel</Button>
<Button
onClick={() => {
onClose();
trackRecommendCheck({
action: "close",
from: recommendRerun ? "rerun" : "initial",
nodes: numNodes,
});
}}
>
Cancel
</Button>
<Button
colorScheme="blue"
onClick={() => {
onClose();
performPresetCheck();
setPerformedRecommend(true);
trackRecommendCheck({
action: "execute",
from: recommendRerun ? "rerun" : "initial",
nodes: numNodes,
});
}}
>
Execute on {numNodes} models
Expand Down
1 change: 1 addition & 0 deletions js/src/lib/api/sessionStorageKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ const prefix = "recce";

export const sessionStorageKeys = {
recommendationIgnored: `${prefix}-recommendation-ignored`,
recommendationShowed: `${prefix}-recommendation-showed`,
prevRefreshTimeStamp: `${prefix}-prev-refresh-timestamp`,
};
10 changes: 10 additions & 0 deletions js/src/lib/api/track.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,13 @@ interface SingleEnvironmentProps {
export function trackSingleEnvironment(props: SingleEnvironmentProps) {
amplitude.track("[Experiment] single_environment", props);
}

interface RecommendPresetCheckProps {
action: "recommend" | "ignore" | "perform" | "execute" | "close";
from?: "initial" | "rerun";
nodes?: number;
}

export function trackRecommendCheck(props: RecommendPresetCheckProps) {
amplitude.track("[Experiment] recommend_preset_check", props);
}
Loading