• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

stacklok / codegate-ui / 12809054037

16 Jan 2025 12:38PM UTC coverage: 68.451% (-0.2%) from 68.636%
12809054037

push

github

web-flow
refactor: fetch prompts data using react-query (#88)

* refator: split promt fetching from UI state

* refactor: fetch prompts using react query

* .

* Revert "."

This reverts commit 891f248dd.

* fix failing tests

205 of 379 branches covered (54.09%)

Branch coverage included in aggregate %.

18 of 19 new or added lines in 6 files covered. (94.74%)

1 existing line in 1 file now uncovered.

396 of 499 relevant lines covered (79.36%)

29.7 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

69.23
/src/lib/utils.ts
1
import { AlertConversation, Conversation } from "@/api/generated/types.gen";
2
import { MaliciousPkgType, TriggerType } from "@/types";
3
import { clsx, type ClassValue } from "clsx";
4
import { isToday, isYesterday } from "date-fns";
5
import { twMerge } from "tailwind-merge";
6

7
const ONE_DAY_MS = 24 * 60 * 60 * 1000;
8✔
8
const SEVEN_DAYS_MS = 7 * ONE_DAY_MS;
8✔
9
const TEEN_DAYS_MS = 14 * ONE_DAY_MS;
8✔
10
const THTY_DAYS_MS = 30 * ONE_DAY_MS;
8✔
11

12
export function cn(...inputs: ClassValue[]) {
13
  return twMerge(clsx(inputs));
340✔
14
}
15

16
export function extractTitleFromMessage(message: string) {
17
  try {
3✔
18
    const regex = /^(.*)```[\s\S]*?```(.*)$/s;
3✔
19
    const match = message.match(regex);
3✔
20

21
    if (match !== null && match !== undefined) {
3✔
22
      const beforeMarkdown = match[1]?.trim();
1✔
23
      const afterMarkdown = match[2]?.trim();
1✔
24
      const title = beforeMarkdown || afterMarkdown;
1✔
25
      return title;
1✔
26
    }
27

28
    return message.trim();
2✔
29
  } catch {
30
    return message.trim();
×
31
  }
32
}
33

34
function getGroup(differenceInMs: number, promptDate: Date): string {
35
  if (isToday(promptDate)) {
2!
36
    return "Today";
×
37
  }
38
  if (isYesterday(promptDate)) {
2!
39
    return "Yesterday";
×
40
  }
41
  if (differenceInMs <= SEVEN_DAYS_MS) {
2!
42
    return "Previous 7 days";
×
43
  }
44
  if (differenceInMs <= TEEN_DAYS_MS) {
2!
45
    return "Previous 14 days";
2✔
46
  }
47
  if (differenceInMs <= THTY_DAYS_MS) {
×
48
    return "Previous 30 days";
×
49
  }
50
  return "Beyond 30 days";
×
51
}
52

53
export function groupPromptsByRelativeDate(prompts: Conversation[]) {
54
  const promptsSorted = prompts.sort(
2✔
55
    (a, b) =>
UNCOV
56
      new Date(b.conversation_timestamp).getTime() -
×
57
      new Date(a.conversation_timestamp).getTime(),
58
  );
59

60
  const grouped = promptsSorted.reduce(
2✔
61
    (groups, prompt) => {
62
      const promptDate = new Date(prompt.conversation_timestamp);
2✔
63
      const now = new Date();
2✔
64
      const differenceInMs = now.getTime() - promptDate.getTime();
2✔
65
      const group = getGroup(differenceInMs, promptDate);
2✔
66

67
      if (!groups[group]) {
2!
68
        groups[group] = [];
2✔
69
      }
70

71
      (groups[group] ?? []).push(prompt);
2!
72
      return groups;
2✔
73
    },
74
    {} as Record<string, Conversation[]>,
75
  );
76

77
  return grouped;
2✔
78
}
79

80
export function getAllIssues(alerts: AlertConversation[]) {
81
  const groupedTriggerCounts = alerts.reduce<Record<string, number>>(
74✔
82
    (acc, alert) => {
83
      const triggerType: TriggerType = alert.trigger_type;
228✔
84
      if (triggerType) {
228!
85
        acc[triggerType] = (acc[triggerType] || 0) + 1;
228✔
86
      }
87
      return acc;
228✔
88
    },
89
    {},
90
  );
91

92
  const maxCount = Math.max(...Object.values(groupedTriggerCounts));
74✔
93

94
  const sortedTagCounts = Object.entries(groupedTriggerCounts).sort(
74✔
95
    ([, countA], [, countB]) => countB - countA,
62✔
96
  );
97
  return { maxCount, sortedTagCounts };
74✔
98
}
99

100
export function getMaliciousPackages() {
101
  const packageCounts = ([] as { packages: [] }[]).reduce<
×
102
    Record<string, number>
103
  >((acc, prompt) => {
104
    (prompt?.packages ?? []).forEach((pkg) => {
×
105
      acc[pkg] = (acc[pkg] || 0) + 1;
×
106
    });
107
    return acc;
×
108
  }, {});
109

110
  const chartData = Object.entries(packageCounts).map(([pkg, count]) => ({
×
111
    id: pkg,
112
    label: pkg,
113
    value: count,
114
  }));
115

116
  return chartData;
×
117
}
118

119
export function sanitizeQuestionPrompt({
120
  question,
121
  answer,
122
}: {
123
  question: string;
124
  answer: string;
125
}) {
126
  try {
3✔
127
    // it shouldn't be possible to receive the prompt answer without a question
128
    if (!answer) return question;
3!
129

130
    // Check if 'answer' is truthy; if so, try to find and return the text after "Query:"
131
    const index = question.indexOf("Query:");
3✔
132
    if (index !== -1) {
3!
133
      // Return the substring starting right after the first occurrence of "Query:"
134
      // Adding the length of "Query:" to the index to start after it
135
      return question.substring(index + "Query:".length).trim();
×
136
    }
137
    return question;
3✔
138
  } catch (error) {
139
    // Log the error and return the original question as a fallback
140
    console.error("Error processing the question:", error);
×
141
    return question;
×
142
  }
143
}
144

145
export function getMaliciousPackage(
146
  value: AlertConversation["trigger_string"],
147
): string | (MaliciousPkgType & { [key: string]: string }) | null {
148
  if (typeof value === "string") {
293✔
149
    return value;
199✔
150
  }
151

152
  if (typeof value === "object" && value !== null) {
94✔
153
    return value as MaliciousPkgType;
85✔
154
  }
155

156
  return null;
9✔
157
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc