@postgres.ai/shared 4.2.0-pr-1203 → 4.2.0-pr-1203.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@postgres.ai/shared",
3
- "version": "4.2.0-pr-1203",
3
+ "version": "4.2.0-pr-1203.1",
4
4
  "main": "index.js",
5
5
  "types": "index.d.ts",
6
6
  "peerDependencies": {
@@ -6,6 +6,7 @@ import React, { useEffect, useReducer } from 'react';
6
6
  import { Spinner } from '@postgres.ai/shared/components/Spinner';
7
7
  import { closeConnection, establishConnection, restartConnection, } from '@postgres.ai/shared/pages/Logs/wsLogs';
8
8
  import { useWsScroll } from '@postgres.ai/shared/pages/Logs/hooks/useWsScroll';
9
+ import { LOGS_FILTER_KEY, readLogsFilterState } from './utils';
9
10
  import { LAPTOP_WIDTH_PX } from './constants';
10
11
  import { PlusIcon } from './Icons/PlusIcon';
11
12
  const useStyles = makeStyles(() => ({
@@ -102,8 +103,6 @@ export const Logs = ({ api, instanceId }) => {
102
103
  const [isLoading, setIsLoading] = React.useState(true);
103
104
  const targetNode = document.getElementById('logs-container');
104
105
  useWsScroll(isLoading);
105
- const logsFilterState = (localStorage === null || localStorage === void 0 ? void 0 : localStorage.getItem('logsFilter')) &&
106
- (JSON === null || JSON === void 0 ? void 0 : JSON.parse((localStorage === null || localStorage === void 0 ? void 0 : localStorage.getItem('logsFilter')) || ''));
107
106
  const initialState = (obj) => {
108
107
  const filters = {
109
108
  '[DEBUG]': true,
@@ -150,7 +149,7 @@ export const Logs = ({ api, instanceId }) => {
150
149
  throw new Error();
151
150
  }
152
151
  };
153
- const [state, dispatch] = useReducer(reducer, initialState(logsFilterState));
152
+ const [state, dispatch] = useReducer(reducer, initialState(readLogsFilterState()));
154
153
  const FormCheckbox = ({ type }) => {
155
154
  const filterType = state[`[${type}]`];
156
155
  return (_jsxs("span", { onClick: () => {
@@ -169,7 +168,7 @@ export const Logs = ({ api, instanceId }) => {
169
168
  return closeConnection;
170
169
  }, [api, instanceId]);
171
170
  useEffect(() => {
172
- localStorage.setItem('logsFilter', JSON.stringify(state));
171
+ localStorage.setItem(LOGS_FILTER_KEY, JSON.stringify(state));
173
172
  }, [state]);
174
173
  useEffect(() => {
175
174
  const config = { attributes: false, childList: true, subtree: true };
@@ -1,2 +1,4 @@
1
+ export declare const LOGS_FILTER_KEY = "logsFilter";
2
+ export declare const readLogsFilterState: () => Record<string, boolean>;
1
3
  export declare const stringWithoutBrackets: (val: string | undefined) => string;
2
4
  export declare const stringContainsPattern: (target: string, pattern?: string[]) => boolean;
@@ -1,3 +1,22 @@
1
+ export const LOGS_FILTER_KEY = 'logsFilter';
2
+ // The filter state is persisted across reloads, so anything may be sitting under the key by
3
+ // the time the page reads it back. An absent or unusable entry falls back to the defaults the
4
+ // page seeds instead of throwing out of a render or out of a socket message handler.
5
+ export const readLogsFilterState = () => {
6
+ const stored = localStorage.getItem(LOGS_FILTER_KEY);
7
+ if (!stored)
8
+ return {};
9
+ try {
10
+ const parsed = JSON.parse(stored);
11
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
12
+ return {};
13
+ }
14
+ return parsed;
15
+ }
16
+ catch {
17
+ return {};
18
+ }
19
+ };
1
20
  export const stringWithoutBrackets = (val) => String(val).replace(/[[\]]/g, '');
2
21
  export const stringContainsPattern = (target, pattern = [
3
22
  'base.go',
@@ -1,5 +1,5 @@
1
1
  import moment from 'moment';
2
- import { stringContainsPattern, stringWithoutBrackets } from './utils';
2
+ import { readLogsFilterState, stringContainsPattern, stringWithoutBrackets, } from './utils';
3
3
  const logsEndpoint = '/instance/logs';
4
4
  const LOGS_TIME_LIMIT = 20;
5
5
  const LOGS_LINE_LIMIT = 1000;
@@ -32,7 +32,7 @@ export const establishConnection = async (api, instanceId) => {
32
32
  const tag = document.createElement('p');
33
33
  const logLevel = logEntry.split(' ')[3];
34
34
  const logInitiator = logEntry.split(' ')[2];
35
- const logsFilterState = JSON.parse(localStorage.getItem('logsFilter') || '');
35
+ const logsFilterState = readLogsFilterState();
36
36
  const filterInitiators = Object.keys(logsFilterState).some((state) => {
37
37
  if (logsFilterState[state]) {
38
38
  if (state === '[other]') {
@@ -53,8 +53,11 @@ export const establishConnection = async (api, instanceId) => {
53
53
  if (logInitiator === '[ERROR]' || logLevel === '[ERROR]') {
54
54
  tag.classList.add('error-log');
55
55
  }
56
- if (logType === 'message') {
57
- const logEntryTime = moment.utc(logElement.children[0].innerHTML.split(' ').slice(0, 2).join(' '));
56
+ // The container is empty whenever the active filters drop every line received so far,
57
+ // so the oldest entry the trim is measured against may not exist.
58
+ const oldestEntry = logElement.children[0];
59
+ if (logType === 'message' && oldestEntry) {
60
+ const logEntryTime = moment.utc(oldestEntry.innerHTML.split(' ').slice(0, 2).join(' '));
58
61
  const timeDifference = moment(logEntryTime).isValid() &&
59
62
  moment.duration(moment.utc(Date.now()).diff(logEntryTime)).asMinutes();
60
63
  if (logElement.childElementCount > LOGS_LINE_LIMIT &&