From 3d8bc63f26cae1908800d57320dd7aba60366fcb Mon Sep 17 00:00:00 2001 From: Jonathan Summers-Muir Date: Mon, 21 Mar 2022 21:17:03 +0100 Subject: [PATCH] chore: start log preview renderers --- .../DatabaseApiColumnRender.tsx | 22 ++ .../DatabasePostgresColumnRender.tsx | 23 ++ .../interfaces/Settings/Logs/LogSelection.tsx | 173 +++++++-- .../Logs/LogSelectionRendererHandler.tsx | 13 + .../DatabaseApiSelectionRender.tsx | 68 ++++ .../DatabasePostgresSelectionRender.tsx | 67 ++++ .../FunctionInvocationSelectionRender.tsx | 26 ++ .../interfaces/Settings/Logs/LogTable.tsx | 355 ++++++++++++++---- .../Settings/Logs/Logs.constants.ts | 16 +- .../interfaces/Settings/Logs/Logs.types.ts | 7 + .../Settings/Logs/LogsFormatters.tsx | 207 ++++++++++ studio/pages/_app.tsx | 1 + .../project/[ref]/settings/logs/[type].tsx | 12 +- studio/styles/react-data-grid-logs.scss | 45 +++ studio/tailwind.config.js | 8 +- 15 files changed, 913 insertions(+), 130 deletions(-) create mode 100644 studio/components/interfaces/Settings/Logs/LogColumnRenderers/DatabaseApiColumnRender.tsx create mode 100644 studio/components/interfaces/Settings/Logs/LogColumnRenderers/DatabasePostgresColumnRender.tsx create mode 100644 studio/components/interfaces/Settings/Logs/LogSelectionRendererHandler.tsx create mode 100644 studio/components/interfaces/Settings/Logs/LogSelectionRenderers/DatabaseApiSelectionRender.tsx create mode 100644 studio/components/interfaces/Settings/Logs/LogSelectionRenderers/DatabasePostgresSelectionRender.tsx create mode 100644 studio/components/interfaces/Settings/Logs/LogSelectionRenderers/FunctionInvocationSelectionRender.tsx create mode 100644 studio/components/interfaces/Settings/Logs/LogsFormatters.tsx create mode 100644 studio/styles/react-data-grid-logs.scss diff --git a/studio/components/interfaces/Settings/Logs/LogColumnRenderers/DatabaseApiColumnRender.tsx b/studio/components/interfaces/Settings/Logs/LogColumnRenderers/DatabaseApiColumnRender.tsx new file mode 100644 index 00000000000..918398bc33d --- /dev/null +++ b/studio/components/interfaces/Settings/Logs/LogColumnRenderers/DatabaseApiColumnRender.tsx @@ -0,0 +1,22 @@ +import dayjs from 'dayjs' +import { ResponseCodeFormatter } from '../LogsFormatters' + +export default [ + { + formatter: (data: any) => ( +
+
+ + {data.row.metadata[0].request[0].method} + {data.row.metadata[0].request[0].path} +
+
+ + {dayjs(data?.row?.timestamp / 1000).format('DD MMM')} + {dayjs(data?.row?.timestamp / 1000).format('HH:mm:ss')} + +
+
+ ), + }, +] diff --git a/studio/components/interfaces/Settings/Logs/LogColumnRenderers/DatabasePostgresColumnRender.tsx b/studio/components/interfaces/Settings/Logs/LogColumnRenderers/DatabasePostgresColumnRender.tsx new file mode 100644 index 00000000000..39789d28404 --- /dev/null +++ b/studio/components/interfaces/Settings/Logs/LogColumnRenderers/DatabasePostgresColumnRender.tsx @@ -0,0 +1,23 @@ +import dayjs from 'dayjs' +import { SeverityFormatter } from '../LogsFormatters' + +export default [ + { + formatter: (data: any) => ( +
+
+ + {dayjs(data?.row?.timestamp / 1000).format('DD MMM')} + {dayjs(data?.row?.timestamp / 1000).format('HH:mm:ss')} + +
+ +
+
+
+ {data.row.event_message} +
+
+ ), + }, +] diff --git a/studio/components/interfaces/Settings/Logs/LogSelection.tsx b/studio/components/interfaces/Settings/Logs/LogSelection.tsx index f4a37c23abf..60abb7bbc69 100644 --- a/studio/components/interfaces/Settings/Logs/LogSelection.tsx +++ b/studio/components/interfaces/Settings/Logs/LogSelection.tsx @@ -2,67 +2,158 @@ import dayjs from 'dayjs' import { FC } from 'react' import { Typography, IconX, Input } from '@supabase/ui' -import { LogData } from './Logs.types' +import { LogData, QueryType } from './Logs.types' +import JsonEditor from 'components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/JsonEditor/JsonCodeEditor' +import { jsonSyntaxHighlight } from './LogsFormatters' +import DatabaseApiSelectionRender, { + DatabaseApiSelectionHeaderRender, +} from './LogSelectionRenderers/DatabaseApiSelectionRender' +import DatabasePostgresSelectionRender from './LogSelectionRenderers/DatabasePostgresSelectionRender' interface Props { log: LogData onClose: () => void + queryType: QueryType } /** * Log selection display */ -const LogSelection: FC = ({ log, onClose }) => { +const LogSelection: FC = ({ log, onClose, queryType }) => { + // console.log('log in selecion', log) + + console.log('log selection in component', log) + // @ts-ignore + console.log('log response', log?.response) + // @ts-ignore + console.log('log request', log?.request) + + // response highlight + // @ts-ignore + const response = log?.response ? jsonSyntaxHighlight(log.response) : '' + + console.log('output', response) + + const Formatter = () => { + switch (queryType) { + case 'api': + return + break + + case 'database': + return + break + + default: + return null + break + } + } + + function header() { + switch (queryType) { + case 'api': + return DatabaseApiSelectionHeaderRender(log) + break + + default: + return null + break + } + } + return (
-
-
-
- {dayjs(log.timestamp / 1000).toString()} -
- + {log ? ( + <> +
+
+
+ {/* + {dayjs(log.timestamp / 1000).toString()} + */} +

{header()}

+
+ +
+
-
-
-
-
-
-

Event message

- +
+ {/*
+
+

Event message

+ +
+
+

Metadata

+ +
+
*/} + + {/*
+              

Request

+
+
+
+              

Request

+
+
*/}
-
-

Metadata

- + + ) : ( +
+
+

Select an Event

+

+ Select an Event to view the code snippet (pretty view) or complete JSON payload (raw + view). +

-
+ )}
) } diff --git a/studio/components/interfaces/Settings/Logs/LogSelectionRendererHandler.tsx b/studio/components/interfaces/Settings/Logs/LogSelectionRendererHandler.tsx new file mode 100644 index 00000000000..6efe69f9a2e --- /dev/null +++ b/studio/components/interfaces/Settings/Logs/LogSelectionRendererHandler.tsx @@ -0,0 +1,13 @@ +import { QueryType } from './Logs.types' + +const SelectionRenderHandler = ({ type }: { type: QueryType }) => { + switch (type) { + case 'api': + break + + default: + break + } +} + +export default SelectionRenderHandler diff --git a/studio/components/interfaces/Settings/Logs/LogSelectionRenderers/DatabaseApiSelectionRender.tsx b/studio/components/interfaces/Settings/Logs/LogSelectionRenderers/DatabaseApiSelectionRender.tsx new file mode 100644 index 00000000000..962ab2afa6f --- /dev/null +++ b/studio/components/interfaces/Settings/Logs/LogSelectionRenderers/DatabaseApiSelectionRender.tsx @@ -0,0 +1,68 @@ +import React from 'react' +import { jsonSyntaxHighlight, ResponseCodeFormatter } from '../LogsFormatters' + +const DatabaseApiSelectionRender = ({ log }: any) => { + const request = log?.metadata[0]?.request[0] + const response = log?.metadata[0]?.response[0] + const method = log?.metadata[0]?.request[0]?.method + const status = log?.metadata[0]?.response[0].status_code + const ipAddress = log?.metadata[0]?.request[0].headers[0]?.cf_connecting_ip + const countryOrigin = log?.metadata[0]?.request[0].headers[0]?.cf_ipcountry + const clientInfo = log?.metadata[0]?.request[0].headers[0]?.x_client_info + const referer = log?.metadata[0]?.request[0].headers[0]?.referer + + const DetailedRow = ({ label, value }: { label: string; value: string | React.ReactNode }) => { + return ( +
+ {label} + {value} +
+ ) + } + + return ( + <> +
+ } /> + + + + + {clientInfo && } + {referer && } +
+
+

Request body

+
+          
+
+
+
+

+ Response{method ? ` ${method}` : null} body +

+
+          
+
+
+ + ) +} + +export const DatabaseApiSelectionHeaderRender = (log: any) => { + const method = log?.metadata[0]?.request[0]?.method + const path = log?.metadata[0]?.request[0]?.path + + return `${method} ${path}` +} + +export default DatabaseApiSelectionRender diff --git a/studio/components/interfaces/Settings/Logs/LogSelectionRenderers/DatabasePostgresSelectionRender.tsx b/studio/components/interfaces/Settings/Logs/LogSelectionRenderers/DatabasePostgresSelectionRender.tsx new file mode 100644 index 00000000000..ee7bef6c0f0 --- /dev/null +++ b/studio/components/interfaces/Settings/Logs/LogSelectionRenderers/DatabasePostgresSelectionRender.tsx @@ -0,0 +1,67 @@ +import { Alert } from '@supabase/ui' +import React from 'react' +import { jsonSyntaxHighlight, SeverityFormatter } from '../LogsFormatters' + +const DatabasePostgresSelectionRender = ({ log }: any) => { + const postgresUsername = log?.metadata[0]?.parsed[0]?.user_name + const sessionId = log?.metadata[0]?.parsed[0]?.session_id + const hint = log?.metadata[0]?.parsed[0]?.hint + + const DetailedRow = ({ label, value }: { label: string; value: string | React.ReactNode }) => { + return ( +
+ {label} + {value} +
+ ) + } + + return ( + <> +
+ Event message + +
+
+
+
+ } /> + + +
+ + {hint && ( +
+ +
+ )} + +
+
+

Metadata

+
+          
+
+
+ + ) +} + +export const DatabaseApiSelectionHeaderRender = (log: any) => { + const method = log?.metadata[0]?.request[0]?.method + const path = log?.metadata[0]?.request[0]?.path + + return `${method} ${path}` +} + +export default DatabasePostgresSelectionRender diff --git a/studio/components/interfaces/Settings/Logs/LogSelectionRenderers/FunctionInvocationSelectionRender.tsx b/studio/components/interfaces/Settings/Logs/LogSelectionRenderers/FunctionInvocationSelectionRender.tsx new file mode 100644 index 00000000000..ab964221126 --- /dev/null +++ b/studio/components/interfaces/Settings/Logs/LogSelectionRenderers/FunctionInvocationSelectionRender.tsx @@ -0,0 +1,26 @@ +import { jsonSyntaxHighlight } from '../LogsFormatters' + +const FunctionInvocationSelectionRender = ({ log }: any) => { + return ( + <> +
+        

Request

+
+
+
+        

Response

+
+
+ + ) +} + +export default FunctionInvocationSelectionRender diff --git a/studio/components/interfaces/Settings/Logs/LogTable.tsx b/studio/components/interfaces/Settings/Logs/LogTable.tsx index 495cf253833..156fa69394a 100644 --- a/studio/components/interfaces/Settings/Logs/LogTable.tsx +++ b/studio/components/interfaces/Settings/Logs/LogTable.tsx @@ -1,15 +1,21 @@ import dayjs from 'dayjs' import { useEffect, useState, useMemo } from 'react' -import { Typography } from '@supabase/ui' -import DataGrid from '@supabase/react-data-grid' +import { Badge, Button, IconDownload, IconDownloadCloud, IconEye, Typography } from '@supabase/ui' +import DataGrid, { Row } from '@supabase/react-data-grid' import LogSelection from './LogSelection' -import { LogData } from './Logs.types' +import { LogData, Mode, QueryType } from './Logs.types' import { isNil } from 'lodash' +import { SeverityFormatter, ResponseCodeFormatter, HeaderFormmater } from './LogsFormatters' + +// column renders +import DatabaseApiColumnRender from './LogColumnRenderers/DatabaseApiColumnRender' +import DatabasePostgresColumnRender from './LogColumnRenderers/DatabasePostgresColumnRender' interface Props { isCustomQuery: boolean data?: Array + queryType: QueryType } type LogMap = { [id: string]: LogData } @@ -18,43 +24,180 @@ type LogMap = { [id: string]: LogData } * * When in custom data display mode, the side panel will not open when focusing on logs. */ -const LogTable = ({ isCustomQuery, data = [] }: Props) => { +const LogTable = ({ isCustomQuery, data = [], queryType }: Props) => { const [focusedLog, setFocusedLog] = useState(null) const columnNames = Object.keys(data[0] || {}) - // whether the data structure is LogData format. - const hasLogDataFormat = - columnNames.includes('timestamp') && - columnNames.includes('event_message') && - columnNames.length === 4 - const columns = (hasLogDataFormat ? ['timestamp', 'event_message'] : columnNames).map((v) => ({ - key: v, - name: v, - width: hasLogDataFormat && v === 'timestamp' ? 210 : undefined, - resizable: true, - headerRenderer: () => { - return
{v}
- }, - formatter: ({ row }: any) => { - let value = row[v] - if (hasLogDataFormat && v === 'timestamp') { - value = dayjs(Number(row['timestamp']) / 1000).toISOString() + console.log('queryType', queryType) + + // console.log('focusedLog', focusedLog) + + isCustomQuery = false + + // whether the data structure is LogData format. + // const hasLogDataFormat = + // columnNames.includes('timestamp') && + // columnNames.includes('event_message') && + // columnNames.length === 4 + + const hasLogDataFormat = !isCustomQuery + + const DEFAULT_COLUMNS = (hasLogDataFormat ? ['timestamp', 'event_message'] : columnNames).map( + (v) => ({ + key: v, + name: v, + width: hasLogDataFormat && v === 'timestamp' ? 210 : undefined, + resizable: true, + headerRenderer: () => { + return
{v}
+ }, + formatter: ({ row }: any) => { + let value = row[v] + if (hasLogDataFormat && v === 'timestamp') { + value = dayjs(Number(row['timestamp']) / 1000).toISOString() + } + return ( +

+ {value} +

+ ) + }, + }) + ) + + let columns + + console.log('QUERY TYPE', queryType) + + switch (queryType) { + case 'api': + if (isCustomQuery) { + columns = DEFAULT_COLUMNS + break } - return ( -

- {value} -

- ) - }, - })) - - const stringData = JSON.stringify(data) + + console.log('is api, running column') + columns = DatabaseApiColumnRender + + break + + case 'database': + if (isCustomQuery) { + columns = DEFAULT_COLUMNS + break + } + + console.log('is api, running column') + columns = DatabasePostgresColumnRender + + break + + case 'fn_edge': + if (isCustomQuery) { + columns = DEFAULT_COLUMNS + break + } + + columns = [ + { + key: 'timestamp', + headerRenderer: () => ( +
+ +
+ ), + name: 'timestamp', + formatter: (data: any) => ( + + {dayjs(data?.row?.timestamp / 1000).format('DD MMM')} + + {dayjs(data?.row?.timestamp / 1000).format('HH:mm:ss')} + + {/* {data?.row?.timestamp} */} + + ), + width: 128, + }, + { + key: 'status_code', + headerRenderer: () => , + name: 'status_code', + formatter: (data: any) => ( + + ), + + width: 0, + resizable: true, + }, + { + key: 'method', + headerRenderer: () => , + width: 0, + resizable: true, + }, + { + key: 'id', + headerRenderer: () => , + name: 'id', + resizable: true, + }, + ] + break + case 'functions': + if (isCustomQuery) { + columns = DEFAULT_COLUMNS + break + } + columns = [ + { + key: 'timestamp', + headerRenderer: () => ( +
+ +
+ ), + name: 'timestamp', + formatter: (data: any) => ( + + + {dayjs(data?.row?.timestamp / 1000).format('DD MMM')} + + + {dayjs(data?.row?.timestamp / 1000).format('HH:mm:ss')} + + {/* {data?.row?.timestamp} */} + + ), + width: 128, + resizable: true, + }, + { + key: 'level', + headerRenderer: () => , + name: 'level', + formatter: (data: any) => , + width: 24, + resizable: true, + }, + { + key: 'event_message', + headerRenderer: () => , + resizable: true, + }, + ] + break + + default: + columns = DEFAULT_COLUMNS + break + } + const logMap = useMemo(() => { if (!hasLogDataFormat) return {} as LogMap const logData = data as LogData[] @@ -62,17 +205,23 @@ const LogTable = ({ isCustomQuery, data = [] }: Props) => { acc[d.id] = d return acc }, {}) as LogMap - }, [stringData]) + }, [JSON.stringify(data)]) + const stringData = JSON.stringify(data) useEffect(() => { + if (!hasLogDataFormat) return if (isNil(data)) return if (focusedLog && !(focusedLog.id in logMap)) { setFocusedLog(null) - } + } }, [stringData]) if (!data) return null + // console.log(data) + // console.log('logMap', logMap) + // console.log(columns) + // [Joshen] Hmm quite hacky now, but will do const maxHeight = isCustomQuery ? 'calc(100vh - 42px - 10rem)' : 'calc(100vh - 42px - 3rem)' @@ -81,45 +230,103 @@ const LogTable = ({ isCustomQuery, data = [] }: Props) => { return Object.values(logMap).sort((a, b) => b.timestamp - a.timestamp) }, [stringData]) return ( -
- { - if (!hasLogDataFormat) return - setFocusedLog(data[rowIdx] as LogData) - }} - noRowsFallback={ -
- - No data returned from query - + <> + {isCustomQuery && ( +
+
+ {data && data.length ? ( + <> + Query results + {data && data.length} + + ) : ( + Results will be shown below + )} +
+
+ +
- } - columns={columns as any} - rowClass={(r) => { - if (!hasLogDataFormat) return 'cursor-pointer' - const row = r as LogData - return `${row.id === focusedLog?.id ? 'bg-green-800' : 'cursor-pointer'}` - }} - rows={logDataRows} - rowKeyGetter={(r) => { - if (!hasLogDataFormat) return Object.keys(r)[0] - const row = r as LogData - return row.id - }} - onRowClick={(r) => { - if (!hasLogDataFormat) return - const row = r as LogData - setFocusedLog(logMap[row.id]) - }} - /> - {focusedLog && ( -
- setFocusedLog(null)} log={focusedLog} />
)} -
+
+ { + if (!hasLogDataFormat) return + setFocusedLog(data[rowIdx] as LogData) + }} + noRowsFallback={ +
+ + No data returned from query + +
+ } + columns={columns as any} + rowClass={(r) => { + // if (!hasLogDataFormat) return 'cursor-pointer' + const row = r as LogData + + let classes = [] + + //@ts-ignore + // if (row.status_code) { + // const response = parseResponseCode(row.status_code) + // if (response == 'warning') { + // classes.push('!bg-yellow-200 !dark:bg-yellow-100') + // } + // if (response == 'error') { + // classes.push('!bg-red-200') + // } + // } + + classes.push( + `${row.id === focusedLog?.id ? '!bg-scale-400 rdg-row--focussed' : 'cursor-pointer'}` + ) + + return classes.join(' ') + }} + rows={logDataRows} + rowKeyGetter={(r) => { + if (!hasLogDataFormat) return Object.keys(r)[0] + const row = r as LogData + return row.id + }} + onRowClick={(r) => { + // if (!hasLogDataFormat) return + const row = r as LogData + setFocusedLog(logMap[row.id]) + }} + /> + {/* {hasLogDataFormat || + (focusedLog && ( */} +
+ setFocusedLog(null)} + log={focusedLog} + queryType={queryType} + /> +
+ {/* ))} */} +
+ ) } export default LogTable diff --git a/studio/components/interfaces/Settings/Logs/Logs.constants.ts b/studio/components/interfaces/Settings/Logs/Logs.constants.ts index f1aafe8c6cf..df1808e4d45 100644 --- a/studio/components/interfaces/Settings/Logs/Logs.constants.ts +++ b/studio/components/interfaces/Settings/Logs/Logs.constants.ts @@ -172,28 +172,30 @@ LIMIT 100 ] export const LOG_TYPE_LABEL_MAPPING: { [k: string]: string } = { - explorer: "Explorer", + explorer: 'Explorer', api: 'API', database: 'Database', } -export const genDefaultQuery = (table: string, where: string = ''): string => `SELECT - id, timestamp, event_message, metadata -FROM - ${table}${where ? ' WHERE\n ' + where : ''} +export const genDefaultQuery = (table: LogsTableName, where: string = '') => { + console.log('genDefaultQuery table', table) + switch (table) { + case 'edge_logs': + return `SELECT id, timestamp, event_message, metadata +FROM ${table} +${where ? ' WHERE\n ' + where : ''} LIMIT 100 ` export const cleanQuery = (str: string) => str.replace(/\n/g, ' ') // .replace(/\n.*\-\-.*(\n)?$?/, "") - export enum LogsTableName { EDGE = 'edge_logs', POSTGRES = 'postgres_logs', } export const genCountQuery = (table: string): string => `SELECT count(*) as count FROM ${table}` -export const genQueryParams = (params: { [k: string ]: string }) => { +export const genQueryParams = (params: { [k: string]: string }) => { // remove keys which are empty strings, null, or undefined for (const k in params) { const v = params[k] diff --git a/studio/components/interfaces/Settings/Logs/Logs.types.ts b/studio/components/interfaces/Settings/Logs/Logs.types.ts index 06b868a0ff1..0a3a2d5617c 100644 --- a/studio/components/interfaces/Settings/Logs/Logs.types.ts +++ b/studio/components/interfaces/Settings/Logs/Logs.types.ts @@ -3,6 +3,7 @@ interface Metadata { } export type LogSearchCallback = (filters: { query: string; to?: string; from?: string; fromMicro?: number, toMicro?: number }) => void +export type LogSearchCallback = (filters: { query: string; to?: string; toMicro?: number }) => void export interface LogsEndpointParams { // project ref project: string @@ -44,3 +45,9 @@ type LFResponse = { export type Count = LFResponse export type Logs = LFResponse + +export type QueryType = 'api' | 'database' | 'functions' | 'fn_edge' | 'sql' + +export type Mode = 'simple' | 'custom' + +export type Table = 'edge_logs' | 'postgres_logs' diff --git a/studio/components/interfaces/Settings/Logs/LogsFormatters.tsx b/studio/components/interfaces/Settings/Logs/LogsFormatters.tsx new file mode 100644 index 00000000000..d5379592c71 --- /dev/null +++ b/studio/components/interfaces/Settings/Logs/LogsFormatters.tsx @@ -0,0 +1,207 @@ +/* + * Response Code + * + * for http response codes + */ + +import { IconAlertCircle, IconInfo } from '@supabase/ui' + +export const ResponseCodeFormatter = ({ value }: any) => { + if (!value) { + return ( +
+ +
+ ) + } + + const split = value.toString().split('')[0] + + // console.log(split) + + switch (split) { + // 2XX || 1XX responses + case '1': + case '2': + return ( +
+
+ +
+
+ ) + break + // 5XX responses + case '5': + return ( +
+
+ +
+
+ ) + break + // 4XX || 3XX responses + case '4': + case '3': + return ( +
+
+ +
+
+ ) + break + // All other responses + default: + return ( +
+
+ +
+
+ ) + break + } +} + +/* + * Response Code + * + * for http response codes + */ + +export const SeverityFormatter = ({ value }: { value: string }) => { + if (!value) { + return ( +
+ +
+ ) + } + + value = value.toLowerCase() + + switch (value) { + case 'error': + return ( +
+
+ +
+ {value} +
+ ) + break + + case 'info': + + case 'debug': + return ( +
+
+ +
+ {value} +
+ ) + break + + case 'log': + return ( +
+
+ +
+ {value} +
+ ) + break + + // All other responses + default: + return ( +
+
+ +
+
+ ) + break + } +} + +/* + * Header Formatter + * + * for http response codes + */ + +export const HeaderFormmater = ({ value }: any) => { + return
{value}
+} + +/* + * JSON Syntax Highlighter + * + * for http response codes + */ + +export function jsonSyntaxHighlight(json: string) { + json = JSON.stringify(json, null, 2) + json = json.replace(/&/g, '&').replace(//g, '>') + + console.log('json', json) + const newJson = json.replace( + /("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, + + function (match) { + var cls = 'number text-tomato-900' + if (/^"/.test(match)) { + if (/:$/.test(match)) { + cls = 'key text-scale-1200' + } else { + cls = 'string text-brand-1100' + } + } else if (/true|false/.test(match)) { + cls = 'boolean text-blue-900' + } else if (/null/.test(match)) { + cls = 'null text-amber-1100' + } + return '' + match + '' + } + ) + + const jsonWithLineWraps = newJson.split(`\n`).map((x) => { + return `${x}` + }) + + return jsonWithLineWraps.join('\n') +} diff --git a/studio/pages/_app.tsx b/studio/pages/_app.tsx index 44600af84cc..c874287d0ca 100644 --- a/studio/pages/_app.tsx +++ b/studio/pages/_app.tsx @@ -7,6 +7,7 @@ import 'styles/toast.scss' import 'styles/code.scss' import 'styles/monaco.scss' import 'styles/contextMenu.scss' +import 'styles/react-data-grid-logs.scss' import Head from 'next/head' import type { AppProps } from 'next/app' diff --git a/studio/pages/project/[ref]/settings/logs/[type].tsx b/studio/pages/project/[ref]/settings/logs/[type].tsx index b1bd96e9d76..e8e9fdedc18 100644 --- a/studio/pages/project/[ref]/settings/logs/[type].tsx +++ b/studio/pages/project/[ref]/settings/logs/[type].tsx @@ -125,7 +125,11 @@ export const LogPage: NextPage = () => { return ( -
+
setShowChart(!showChart)} @@ -153,7 +157,7 @@ export const LogPage: NextPage = () => { }} onSelectTemplate={onSelectTemplate} /> - {showChart && ( + {/* {showChart && (
{ }} />
- )} + )} */}
{isLoading && (
{
)} - +