diff --git a/scripts/helpers/utils.ts b/scripts/helpers/utils.ts index 3abad4f..afc1156 100644 --- a/scripts/helpers/utils.ts +++ b/scripts/helpers/utils.ts @@ -8,7 +8,7 @@ export enum Level { SILLY = "silly", } -export const createGitHubCommentURL = (orgName: string, repoName: string, issueNumber: number, commentId: number) => { +export const createGitHubCommentURL = (orgName: string | null, repoName: string | null, issueNumber: number | null, commentId: number | null) => { return `https://github.com/${orgName}/${repoName}/issues/${issueNumber}#issuecomment-${commentId}`; }; @@ -21,21 +21,21 @@ export const isValidJson = (jsonString: string): boolean => { } }; -export const generateRandomId = (length: Number) => { +export const generateRandomId = (length: number) => { return [...Array(length)].map(() => Math.random().toString(36)[2]).join(""); }; -export const containsValidJson = (message: string): [boolean, string, string] => { - const jsonMatches = message.match(/\{.*\}/g); // Find JSON-like substrings +export const containsValidJson = (message: string | null): [boolean, string, string | undefined] => { + const jsonMatches = message?.match(/\{.*\}/g); // Find JSON-like substrings if (!jsonMatches) { return [false, "", ""]; } for (const match of jsonMatches) { if (isValidJson(match)) { - const braceIndex = message.indexOf("{"); + const braceIndex = message?.indexOf("{"); if (braceIndex !== -1) { - return [true, match, message.substring(0, braceIndex)]; + return [true, match, message?.substring(0, braceIndex)]; } return [true, match, ""]; } @@ -44,7 +44,7 @@ export const containsValidJson = (message: string): [boolean, string, string] => return [false, "", ""]; }; -export const getLevelString = (level: number) => { +export const getLevelString = (level: number | null) => { switch (level) { case 0: return Level.ERROR; diff --git a/scripts/index.ts b/scripts/index.ts index ee5cfcf..0e11a3a 100644 --- a/scripts/index.ts +++ b/scripts/index.ts @@ -1,5 +1,6 @@ import { containsValidJson, createGitHubCommentURL, generateRandomId, getLevelString } from "./helpers/utils"; import { Logs } from "./types/log"; +import { Database } from "../types/supabase"; import { createClient } from "@supabase/supabase-js"; import { SUPABASE_URL, SUPABASE_KEY } from "./constants/index"; @@ -11,6 +12,8 @@ const jsonModal = document.getElementById("json-modal") as HTMLDivElement; const closeModalButton = document.getElementById("close-modal") as HTMLButtonElement; const jsonContent = document.getElementById("json-content") as HTMLDivElement; +let isLoading = false; + const openJsonModal = (validJson: string) => { jsonContent.textContent = validJson; @@ -48,14 +51,49 @@ const updateLogTable = () => { } }); } - // scroll to last added data - logCell[logCell.length - 1].scrollIntoView(); }); }; let logs: Logs[] = []; -const supabaseClient = createClient(SUPABASE_URL, SUPABASE_KEY); +const supabaseClient = createClient(SUPABASE_URL, SUPABASE_KEY); + +const fetchData = async () => { + isLoading = true; + + if (logs.length > 0) { + const firstAvailableTimestamp = logs.at(logs.length-1)?.timestamp; + const { data, error } = await supabaseClient + .from("logs") + .select() + .lt("timestamp", firstAvailableTimestamp) + .order("timestamp", { ascending: false }) + .limit(25); + if (data && data.length > 0) { + logs.push(...data); + updateLogTable(); + } else console.log(error); + } else { + const { data, error } = await supabaseClient.from("logs").select().order("timestamp", { ascending: false }).limit(30); + if (data && data.length > 0) { + logs.push(...data); + updateLogTable(); + } else console.log(error); + } + + isLoading = false; +}; + +const handleScroll = async () => { + const bottom = document.documentElement.scrollHeight - document.documentElement.scrollTop === document.documentElement.clientHeight; + + if (!bottom || isLoading) { + return; + } + await fetchData(); +}; + +window.addEventListener("scroll", handleScroll); supabaseClient .channel("table-db-changes") @@ -72,7 +110,7 @@ supabaseClient const handlePayload = (logEntry: any) => { if (logEntry?.eventType !== "INSERT") return; - logs.push(logEntry.new); + logs.unshift(logEntry.new); updateLogTable(); }; @@ -93,7 +131,9 @@ window.addEventListener("click", (event) => { if (event.target === jsonModal) { jsonModal.style.display = "none"; } + isLoading = !isLoading; }); // Initial update +fetchData(); updateLogTable(); diff --git a/scripts/types/log.ts b/scripts/types/log.ts index ebd2b43..37cd908 100644 --- a/scripts/types/log.ts +++ b/scripts/types/log.ts @@ -1,9 +1,10 @@ export type Logs = { - timestamp: string; - log_message: string; - level: number; - repo_name: string; - org_name: string; - comment_id: number; - issue_number: number; + comment_id: number | null; + id: number; + issue_number: number | null; + level: number | null; + log_message: string | null; + org_name: string | null; + repo_name: string | null; + timestamp: string | null; }; diff --git a/types/supabase.ts b/types/supabase.ts new file mode 100644 index 0000000..2a01c75 --- /dev/null +++ b/types/supabase.ts @@ -0,0 +1,426 @@ +export type Json = string | number | boolean | null | { [key: string]: Json | undefined } | Json[]; + +export interface Database { + public: { + Tables: { + access: { + Row: { + created_at: string | null; + multiplier_access: boolean | null; + price_access: boolean | null; + priority_access: boolean | null; + repository: string; + time_access: boolean | null; + updated_at: string | null; + user_name: string; + }; + Insert: { + created_at?: string | null; + multiplier_access?: boolean | null; + price_access?: boolean | null; + priority_access?: boolean | null; + repository: string; + time_access?: boolean | null; + updated_at?: string | null; + user_name: string; + }; + Update: { + created_at?: string | null; + multiplier_access?: boolean | null; + price_access?: boolean | null; + priority_access?: boolean | null; + repository?: string; + time_access?: boolean | null; + updated_at?: string | null; + user_name?: string; + }; + Relationships: []; + }; + debits: { + Row: { + amount: number; + created_at: string; + id: number; + updated_at: string; + }; + Insert: { + amount: number; + created_at: string; + id?: number; + updated_at: string; + }; + Update: { + amount?: number; + created_at?: string; + id?: number; + updated_at?: string; + }; + Relationships: []; + }; + issues: { + Row: { + assignees: string[] | null; + closed_at: string | null; + comments_url: string; + completed_at: string | null; + created_at: string | null; + events_url: string; + id: number; + issue_number: number; + issue_url: string; + labels: string[] | null; + price: string | null; + priority: string | null; + recipient: string | null; + started_at: string | null; + status: Database["public"]["Enums"]["issue_status"]; + timeline: string | null; + txhash: string[] | null; + updated_at: string | null; + }; + Insert: { + assignees?: string[] | null; + closed_at?: string | null; + comments_url: string; + completed_at?: string | null; + created_at?: string | null; + events_url: string; + id?: number; + issue_number: number; + issue_url: string; + labels?: string[] | null; + price?: string | null; + priority?: string | null; + recipient?: string | null; + started_at?: string | null; + status?: Database["public"]["Enums"]["issue_status"]; + timeline?: string | null; + txhash?: string[] | null; + updated_at?: string | null; + }; + Update: { + assignees?: string[] | null; + closed_at?: string | null; + comments_url?: string; + completed_at?: string | null; + created_at?: string | null; + events_url?: string; + id?: number; + issue_number?: number; + issue_url?: string; + labels?: string[] | null; + price?: string | null; + priority?: string | null; + recipient?: string | null; + started_at?: string | null; + status?: Database["public"]["Enums"]["issue_status"]; + timeline?: string | null; + txhash?: string[] | null; + updated_at?: string | null; + }; + Relationships: []; + }; + label_changes: { + Row: { + authorized: boolean; + created: string; + id: number; + label_from: string; + label_to: string; + repository: string; + updated: string; + username: string; + }; + Insert: { + authorized: boolean; + created: string; + id?: number; + label_from: string; + label_to: string; + repository: string; + updated: string; + username: string; + }; + Update: { + authorized?: boolean; + created?: string; + id?: number; + label_from?: string; + label_to?: string; + repository?: string; + updated?: string; + username?: string; + }; + Relationships: []; + }; + logs: { + Row: { + comment_id: number | null; + id: number; + issue_number: number | null; + level: number | null; + log_message: string | null; + org_name: string | null; + repo_name: string | null; + timestamp: string | null; + }; + Insert: { + comment_id?: number | null; + id?: number; + issue_number?: number | null; + level?: number | null; + log_message?: string | null; + org_name?: string | null; + repo_name?: string | null; + timestamp?: string | null; + }; + Update: { + comment_id?: number | null; + id?: number; + issue_number?: number | null; + level?: number | null; + log_message?: string | null; + org_name?: string | null; + repo_name?: string | null; + timestamp?: string | null; + }; + Relationships: []; + }; + multiplier: { + Row: { + created_at: string | null; + reason: string | null; + updated_at: string | null; + user_id: string; + value: number | null; + }; + Insert: { + created_at?: string | null; + reason?: string | null; + updated_at?: string | null; + user_id: string; + value?: number | null; + }; + Update: { + created_at?: string | null; + reason?: string | null; + updated_at?: string | null; + user_id?: string; + value?: number | null; + }; + Relationships: []; + }; + penalty: { + Row: { + amount: string; + network_id: string; + repository_name: string; + token_address: string; + username: string; + }; + Insert: { + amount?: string; + network_id: string; + repository_name: string; + token_address: string; + username: string; + }; + Update: { + amount?: string; + network_id?: string; + repository_name?: string; + token_address?: string; + username?: string; + }; + Relationships: []; + }; + permits: { + Row: { + bounty_hunter_address: string; + bounty_hunter_id: number; + created_at: string; + deadline: string; + id: number; + issue_id: number; + network_id: number; + nonce: string; + organization_id: number | null; + payout_amount: string; + repository_id: number; + signature: string; + token_address: string; + wallet_owner_address: string; + }; + Insert: { + bounty_hunter_address: string; + bounty_hunter_id: number; + created_at: string; + deadline: string; + id?: number; + issue_id: number; + network_id: number; + nonce: string; + organization_id?: number | null; + payout_amount: string; + repository_id: number; + signature: string; + token_address: string; + wallet_owner_address: string; + }; + Update: { + bounty_hunter_address?: string; + bounty_hunter_id?: number; + created_at?: string; + deadline?: string; + id?: number; + issue_id?: number; + network_id?: number; + nonce?: string; + organization_id?: number | null; + payout_amount?: string; + repository_id?: number; + signature?: string; + token_address?: string; + wallet_owner_address?: string; + }; + Relationships: []; + }; + users: { + Row: { + bio: string | null; + blog: string | null; + company: string | null; + contributions: string | null; + created_at: string | null; + email: string | null; + followers: number | null; + following: number | null; + percent_code_reviews: number | null; + percent_commits: number | null; + percent_issues: number | null; + percent_pull_requests: number | null; + public_repos: number | null; + twitter_username: string | null; + updated_at: string | null; + user_location: string | null; + user_login: string; + user_name: string; + user_type: string | null; + wallet_address: string | null; + }; + Insert: { + bio?: string | null; + blog?: string | null; + company?: string | null; + contributions?: string | null; + created_at?: string | null; + email?: string | null; + followers?: number | null; + following?: number | null; + percent_code_reviews?: number | null; + percent_commits?: number | null; + percent_issues?: number | null; + percent_pull_requests?: number | null; + public_repos?: number | null; + twitter_username?: string | null; + updated_at?: string | null; + user_location?: string | null; + user_login: string; + user_name: string; + user_type?: string | null; + wallet_address?: string | null; + }; + Update: { + bio?: string | null; + blog?: string | null; + company?: string | null; + contributions?: string | null; + created_at?: string | null; + email?: string | null; + followers?: number | null; + following?: number | null; + percent_code_reviews?: number | null; + percent_commits?: number | null; + percent_issues?: number | null; + percent_pull_requests?: number | null; + public_repos?: number | null; + twitter_username?: string | null; + updated_at?: string | null; + user_location?: string | null; + user_login?: string; + user_name?: string; + user_type?: string | null; + wallet_address?: string | null; + }; + Relationships: []; + }; + wallets: { + Row: { + created_at: string | null; + updated_at: string | null; + user_name: string; + wallet_address: string | null; + }; + Insert: { + created_at?: string | null; + updated_at?: string | null; + user_name: string; + wallet_address?: string | null; + }; + Update: { + created_at?: string | null; + updated_at?: string | null; + user_name?: string; + wallet_address?: string | null; + }; + Relationships: []; + }; + weekly: { + Row: { + created_at: string | null; + last_time: string | null; + }; + Insert: { + created_at?: string | null; + last_time?: string | null; + }; + Update: { + created_at?: string | null; + last_time?: string | null; + }; + Relationships: []; + }; + }; + Views: { + [_ in never]: never; + }; + Functions: { + add_penalty: { + Args: { + _username: string; + _repository_name: string; + _network_id: string; + _token_address: string; + _penalty_amount: string; + }; + Returns: string; + }; + remove_penalty: { + Args: { + _username: string; + _repository_name: string; + _network_id: string; + _token_address: string; + _penalty_amount: string; + }; + Returns: string; + }; + }; + Enums: { + issue_status: "READY_TO_START" | "IN_PROGRESS" | "IN_REVIEW" | "DONE"; + }; + CompositeTypes: { + [_ in never]: never; + }; + }; +}