mirror of
https://github.com/gravitational/teleport
synced 2024-10-19 08:43:58 +00:00
Remove usage of lodash methods (#21567)
* Create new local util lib to replace lodash. * Replace usage of isInteger and debounce from lodash with highbar. * Create isObject and runOnce utility methods. * remove use of at, isObject, and once lodash method usage. * remove map and transform lodash calls. * Add memoize function to highbar. * remove memoize lodash usage. * remove merge and isEqual lodash methods and update other missing refs to highbar. * convert the throttle to debounce. * add throttle method to highbar. * use the new throttle method instead of debounce where necessary. * Add mergeDeep function for init config merge. * remove lodash from the build process. * Fix introduced bug in workspacesService. * Added tests for highbar mergeDeep and expanded its functionality to support arrays. * review updates. * Added types to mergeDeep function. * Add missing MapCache prototype methods. * Add license notices, types and missing hash code. * First pass at compare an array objects function. * use new compareArrayObjs fn * Add missing not * Added types to arrayObjectIsEqual * Add tests for arrayObjectIsEqual and fix some edge case bugs. * update util fn name
This commit is contained in:
parent
2f0c97d276
commit
5eafe86fa4
|
@ -57,7 +57,6 @@ module.exports = {
|
||||||
plugins: [
|
plugins: [
|
||||||
...plugins,
|
...plugins,
|
||||||
['babel-plugin-styled-components', { displayName: false, ssr: false }],
|
['babel-plugin-styled-components', { displayName: false, ssr: false }],
|
||||||
'babel-plugin-lodash',
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -45,7 +45,6 @@
|
||||||
"@testing-library/react-hooks": "^8.0.1",
|
"@testing-library/react-hooks": "^8.0.1",
|
||||||
"@testing-library/user-event": "^14.4.3",
|
"@testing-library/user-event": "^14.4.3",
|
||||||
"@types/jest": "^27.3.1",
|
"@types/jest": "^27.3.1",
|
||||||
"@types/lodash": "4.14.149",
|
|
||||||
"@types/node": "^16.11.10",
|
"@types/node": "^16.11.10",
|
||||||
"@types/react": "^16.8.19",
|
"@types/react": "^16.8.19",
|
||||||
"@types/react-router-dom": "^4.3.3",
|
"@types/react-router-dom": "^4.3.3",
|
||||||
|
@ -55,7 +54,6 @@
|
||||||
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
||||||
"@typescript-eslint/parser": "^5.4.0",
|
"@typescript-eslint/parser": "^5.4.0",
|
||||||
"babel-loader": "^8.2.5",
|
"babel-loader": "^8.2.5",
|
||||||
"babel-plugin-lodash": "^3.3.4",
|
|
||||||
"clean-webpack-plugin": "4.0.0",
|
"clean-webpack-plugin": "4.0.0",
|
||||||
"core-js": "^3",
|
"core-js": "^3",
|
||||||
"cross-env": "5.0.5",
|
"cross-env": "5.0.5",
|
||||||
|
@ -76,7 +74,6 @@
|
||||||
"html-webpack-plugin": "^5.5.0",
|
"html-webpack-plugin": "^5.5.0",
|
||||||
"jest": "^27.3.1",
|
"jest": "^27.3.1",
|
||||||
"jest-styled-components": "^7.0.8",
|
"jest-styled-components": "^7.0.8",
|
||||||
"lodash-webpack-plugin": "^0.11.6",
|
|
||||||
"msw": "^0.47.4",
|
"msw": "^0.47.4",
|
||||||
"optimist": "^0.6.1",
|
"optimist": "^0.6.1",
|
||||||
"prettier": "^2.5.0",
|
"prettier": "^2.5.0",
|
||||||
|
|
|
@ -18,7 +18,6 @@ const path = require('path');
|
||||||
|
|
||||||
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
|
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
|
||||||
const HtmlWebPackPlugin = require('html-webpack-plugin');
|
const HtmlWebPackPlugin = require('html-webpack-plugin');
|
||||||
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
|
|
||||||
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
|
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
|
||||||
const ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
|
const ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
|
||||||
|
|
||||||
|
@ -51,9 +50,6 @@ const configFactory = {
|
||||||
...options,
|
...options,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
lodash() {
|
|
||||||
return new LodashModuleReplacementPlugin();
|
|
||||||
},
|
|
||||||
bundleAnalyzer(options) {
|
bundleAnalyzer(options) {
|
||||||
return new BundleAnalyzerPlugin({ analyzerHost: '0.0.0.0', ...options });
|
return new BundleAnalyzerPlugin({ analyzerHost: '0.0.0.0', ...options });
|
||||||
},
|
},
|
||||||
|
|
|
@ -19,7 +19,7 @@ const configFactory = require('./webpack.base');
|
||||||
process.env.BABEL_ENV = 'production';
|
process.env.BABEL_ENV = 'production';
|
||||||
process.env.NODE_ENV = 'production';
|
process.env.NODE_ENV = 'production';
|
||||||
|
|
||||||
const plugins = [configFactory.plugins.lodash()];
|
const plugins = [];
|
||||||
|
|
||||||
if (process.env.WEBPACK_ANALYZE_BUNDLE === 'true') {
|
if (process.env.WEBPACK_ANALYZE_BUNDLE === 'true') {
|
||||||
plugins.push(configFactory.plugins.bundleAnalyzer());
|
plugins.push(configFactory.plugins.bundleAnalyzer());
|
||||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { isObject } from 'lodash';
|
import { isObject } from 'shared/utils/highbar';
|
||||||
|
|
||||||
import Logger from '../../libs/logger';
|
import Logger from '../../libs/logger';
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
"ace-builds": "1.4.6",
|
"ace-builds": "1.4.6",
|
||||||
"create-react-class": "^15.6.3",
|
"create-react-class": "^15.6.3",
|
||||||
"cross-env": "5.0.5",
|
"cross-env": "5.0.5",
|
||||||
"lodash": "^4.17.21",
|
|
||||||
"date-fns": "^2.28.0",
|
"date-fns": "^2.28.0",
|
||||||
"react": "^16.8.4",
|
"react": "^16.8.4",
|
||||||
"react-day-picker": "7.3.2",
|
"react-day-picker": "7.3.2",
|
||||||
|
|
221
web/packages/shared/utils/highbar.test.ts
Normal file
221
web/packages/shared/utils/highbar.test.ts
Normal file
|
@ -0,0 +1,221 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2023 Gravitational, Inc
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { arrayObjectIsEqual, mergeDeep } from './highbar';
|
||||||
|
|
||||||
|
describe('mergeDeep can merge two', () => {
|
||||||
|
it('objects together', () => {
|
||||||
|
const a = { a: 1, b: 2, c: 3, e: 5 };
|
||||||
|
const b = { a: 3, b: 2, c: 1, d: 4 };
|
||||||
|
expect(mergeDeep(a, b)).toStrictEqual({
|
||||||
|
a: 3,
|
||||||
|
b: 2,
|
||||||
|
c: 1,
|
||||||
|
d: 4,
|
||||||
|
e: 5,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('nested objects together', () => {
|
||||||
|
const a = { a: 1, b: 2, c: { d: 3, e: 6, g: 8 } };
|
||||||
|
const b = { a: 1, b: 2, c: { d: 4, e: 6, f: 7 } };
|
||||||
|
expect(mergeDeep(a, b)).toStrictEqual({
|
||||||
|
a: 1,
|
||||||
|
b: 2,
|
||||||
|
c: { d: 4, e: 6, f: 7, g: 8 },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('objects together that contain arrays', () => {
|
||||||
|
const a = { a: 1, b: ['a', 'b', 'd'] };
|
||||||
|
const b = { a: 2, b: ['b', 'c'] };
|
||||||
|
expect(mergeDeep(a, b)).toStrictEqual({
|
||||||
|
a: 2,
|
||||||
|
b: ['b', 'c', 'd'],
|
||||||
|
});
|
||||||
|
|
||||||
|
const c = { a: 1, b: ['b', 'c'] };
|
||||||
|
const d = { a: 2, b: ['a', 'b', 'd'] };
|
||||||
|
expect(mergeDeep(c, d)).toStrictEqual({
|
||||||
|
a: 2,
|
||||||
|
b: ['a', 'b', 'd'],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('objects together that contain arrays of arrays', () => {
|
||||||
|
const a = { a: [['b', 'c', 'f']] };
|
||||||
|
const b = { a: [['d', 'e']] };
|
||||||
|
expect(mergeDeep(a, b)).toStrictEqual({
|
||||||
|
a: [['d', 'e', 'f']],
|
||||||
|
});
|
||||||
|
|
||||||
|
const c = { a: [['d', 'e']] };
|
||||||
|
const d = { a: [['b', 'c', 'f']] };
|
||||||
|
expect(mergeDeep(c, d)).toStrictEqual({
|
||||||
|
a: [['b', 'c', 'f']],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('objects together that contain arrays that contain objects', () => {
|
||||||
|
const a = { a: 1, b: [{ c: 3, d: 4, e: 5 }, 'b'] };
|
||||||
|
const b = { a: 2, b: [{ c: 3, d: 4, f: 6 }, 'c'] };
|
||||||
|
expect(mergeDeep(a, b)).toStrictEqual({
|
||||||
|
a: 2,
|
||||||
|
b: [{ c: 3, d: 4, e: 5, f: 6 }, 'c'],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('objects with arrays with undefined indexes', () => {
|
||||||
|
const a = {
|
||||||
|
a: false,
|
||||||
|
b: {
|
||||||
|
c: 'foo',
|
||||||
|
d: 'bar',
|
||||||
|
},
|
||||||
|
c: {
|
||||||
|
a: 'no',
|
||||||
|
b: [],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const b = {
|
||||||
|
a: true,
|
||||||
|
b: {
|
||||||
|
d: 'baz',
|
||||||
|
e: 'bax',
|
||||||
|
},
|
||||||
|
c: {
|
||||||
|
a: 'ok',
|
||||||
|
b: [
|
||||||
|
{
|
||||||
|
a: 'foo',
|
||||||
|
b: 'bar',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
expect(mergeDeep(a, b)).toStrictEqual({
|
||||||
|
a: true,
|
||||||
|
b: {
|
||||||
|
c: 'foo',
|
||||||
|
d: 'baz',
|
||||||
|
e: 'bax',
|
||||||
|
},
|
||||||
|
c: {
|
||||||
|
a: 'ok',
|
||||||
|
b: [
|
||||||
|
{
|
||||||
|
a: 'foo',
|
||||||
|
b: 'bar',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('arrayObjectIsEqual correctly compares', () => {
|
||||||
|
it('simple arrays', () => {
|
||||||
|
const a = [{ foo: 'bar' }];
|
||||||
|
const b = [{ foo: 'bar' }];
|
||||||
|
|
||||||
|
expect(arrayObjectIsEqual(a, b)).toBe(true);
|
||||||
|
|
||||||
|
const c = [{ foo: 'bar' }];
|
||||||
|
const d = [{ foo: 'baz' }];
|
||||||
|
expect(arrayObjectIsEqual(c, d)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('arrays with complex objects', () => {
|
||||||
|
const a = [
|
||||||
|
{
|
||||||
|
'/clusters/test-uri': {
|
||||||
|
accessRequests: {
|
||||||
|
pending: {
|
||||||
|
app: {},
|
||||||
|
db: {},
|
||||||
|
kube_cluster: {},
|
||||||
|
node: {},
|
||||||
|
role: {},
|
||||||
|
windows_desktop: {},
|
||||||
|
},
|
||||||
|
isBarCollapsed: false,
|
||||||
|
},
|
||||||
|
localClusterUri: '/clusters/test-uri',
|
||||||
|
documents: [
|
||||||
|
{
|
||||||
|
kind: 'doc.cluster',
|
||||||
|
title: 'Cluster Test',
|
||||||
|
clusterUri: '/clusters/test-uri',
|
||||||
|
uri: '/docs/test-cluster-uri',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
location: '/docs/test-cluster-uri',
|
||||||
|
previous: {
|
||||||
|
documents: [
|
||||||
|
{
|
||||||
|
kind: 'doc.terminal_shell',
|
||||||
|
uri: '/docs/some_uri',
|
||||||
|
title: '/Users/alice/Documents',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
location: '/docs/some_uri',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const b = [
|
||||||
|
{
|
||||||
|
'/clusters/test-uri': {
|
||||||
|
accessRequests: {
|
||||||
|
pending: {
|
||||||
|
app: {},
|
||||||
|
db: {},
|
||||||
|
kube_cluster: {},
|
||||||
|
node: {},
|
||||||
|
role: {},
|
||||||
|
windows_desktop: {},
|
||||||
|
},
|
||||||
|
isBarCollapsed: false,
|
||||||
|
},
|
||||||
|
localClusterUri: '/clusters/test-uri',
|
||||||
|
documents: [
|
||||||
|
{
|
||||||
|
kind: 'doc.cluster',
|
||||||
|
title: 'Cluster Test',
|
||||||
|
clusterUri: '/clusters/test-uri',
|
||||||
|
uri: '/docs/test-cluster-uri',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
location: '/docs/test-cluster-uri',
|
||||||
|
previous: {
|
||||||
|
documents: [
|
||||||
|
{
|
||||||
|
kind: 'doc.terminal_shell',
|
||||||
|
uri: '/docs/some_uri',
|
||||||
|
title: '/Users/alice/Documents',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
location: '/docs/some_uri',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
expect(arrayObjectIsEqual(a, b)).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
459
web/packages/shared/utils/highbar.ts
Normal file
459
web/packages/shared/utils/highbar.ts
Normal file
|
@ -0,0 +1,459 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2023 Gravitational, Inc
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
type SupportedMergeTypes = string | number | Record<string, unknown>;
|
||||||
|
type MergeTarget = Record<string, unknown> | Array<SupportedMergeTypes>;
|
||||||
|
|
||||||
|
export function mergeDeep(target: MergeTarget, ...sources: Array<MergeTarget>) {
|
||||||
|
const isObject = obj => obj && typeof obj === 'object' && !Array.isArray(obj);
|
||||||
|
|
||||||
|
const mergeArray = (target, source) => {
|
||||||
|
source.forEach((value, index) => {
|
||||||
|
if (
|
||||||
|
Array.isArray(value) ||
|
||||||
|
(isObject(value) && isObject(source[index]))
|
||||||
|
) {
|
||||||
|
if (target[index] === undefined) {
|
||||||
|
target[index] = source[index];
|
||||||
|
} else {
|
||||||
|
mergeDeep(target[index], source[index]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
target[index] = source[index];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!sources.length) return target;
|
||||||
|
const source = sources.shift();
|
||||||
|
|
||||||
|
if (isObject(target) && isObject(source)) {
|
||||||
|
for (const key in source) {
|
||||||
|
if (isObject(source[key])) {
|
||||||
|
if (!target[key]) Object.assign(target, { [key]: {} });
|
||||||
|
mergeDeep(target[key], source[key]);
|
||||||
|
} else if (Array.isArray(source[key])) {
|
||||||
|
mergeArray(target[key], source[key]);
|
||||||
|
} else {
|
||||||
|
Object.assign(target, { [key]: source[key] });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (Array.isArray(target) && Array.isArray(source)) {
|
||||||
|
mergeArray(target, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mergeDeep(target, ...sources);
|
||||||
|
}
|
||||||
|
|
||||||
|
type CompareArray = Array<Record<string, unknown>>;
|
||||||
|
|
||||||
|
export function arrayObjectIsEqual(
|
||||||
|
arr1: CompareArray,
|
||||||
|
arr2: CompareArray
|
||||||
|
): boolean {
|
||||||
|
const compareArrays = (arr1, arr2) =>
|
||||||
|
arr1.length === arr2.length &&
|
||||||
|
arr1.every((obj, idx) => compareObjects(obj, arr2[idx]));
|
||||||
|
|
||||||
|
const compareObjects = (obj1, obj2) => {
|
||||||
|
if (!isObject(obj1)) {
|
||||||
|
return obj1 === obj2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Object.keys(obj1).length) {
|
||||||
|
if (Object.keys(obj1).length !== Object.keys(obj2).length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return Object.keys(obj1).every(key => {
|
||||||
|
return compareObjects(obj1[key], obj2[key]);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return compareArrays(arr1, arr2);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isInteger(checkVal: any): boolean {
|
||||||
|
return Number.isInteger(checkVal) || checkVal == parseInt(checkVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isObject(checkVal: unknown): boolean {
|
||||||
|
const type = typeof checkVal;
|
||||||
|
return checkVal != null && (type == 'object' || type == 'function');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lodash <https://lodash.com/>
|
||||||
|
* Copyright JS Foundation and other contributors <https://js.foundation/>
|
||||||
|
* Released under MIT license <https://lodash.com/license>
|
||||||
|
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
|
||||||
|
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
||||||
|
*/
|
||||||
|
export function runOnce<T extends (...args) => any>(func: T) {
|
||||||
|
let n = 2;
|
||||||
|
let result;
|
||||||
|
return function () {
|
||||||
|
if (--n > 0) {
|
||||||
|
result = func.apply(this, arguments);
|
||||||
|
}
|
||||||
|
if (n <= 1) {
|
||||||
|
func = undefined;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ThrottleSettings {
|
||||||
|
leading?: boolean | undefined;
|
||||||
|
trailing?: boolean | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lodash <https://lodash.com/>
|
||||||
|
* Copyright JS Foundation and other contributors <https://js.foundation/>
|
||||||
|
* Released under MIT license <https://lodash.com/license>
|
||||||
|
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
|
||||||
|
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
||||||
|
*/
|
||||||
|
export function throttle<T extends (...args: any) => any>(
|
||||||
|
func: T,
|
||||||
|
wait = 0,
|
||||||
|
options?: ThrottleSettings
|
||||||
|
): DebouncedFunc<T> {
|
||||||
|
var leading = true,
|
||||||
|
trailing = true;
|
||||||
|
|
||||||
|
if (isObject(options)) {
|
||||||
|
leading = 'leading' in options ? !!options.leading : leading;
|
||||||
|
trailing = 'trailing' in options ? !!options.trailing : trailing;
|
||||||
|
}
|
||||||
|
return debounce(func, wait, {
|
||||||
|
leading: leading,
|
||||||
|
maxWait: wait,
|
||||||
|
trailing: trailing,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DebouncedFunc<T extends (...args: any[]) => any> = {
|
||||||
|
(...args: Parameters<T>): ReturnType<T> | undefined;
|
||||||
|
cancel(): void;
|
||||||
|
flush(): ReturnType<T> | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
type DebounceSettings = {
|
||||||
|
leading?: boolean | undefined;
|
||||||
|
maxWait?: number | undefined;
|
||||||
|
trailing?: boolean | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lodash <https://lodash.com/>
|
||||||
|
* Copyright JS Foundation and other contributors <https://js.foundation/>
|
||||||
|
* Released under MIT license <https://lodash.com/license>
|
||||||
|
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
|
||||||
|
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
||||||
|
*/
|
||||||
|
export function debounce<T extends (...args: any) => any>(
|
||||||
|
func: T,
|
||||||
|
wait = 0,
|
||||||
|
options?: DebounceSettings
|
||||||
|
): DebouncedFunc<T> {
|
||||||
|
var lastArgs,
|
||||||
|
lastThis,
|
||||||
|
maxWait,
|
||||||
|
result,
|
||||||
|
timerId,
|
||||||
|
lastCallTime,
|
||||||
|
lastInvokeTime = 0,
|
||||||
|
leading = false,
|
||||||
|
maxing = false,
|
||||||
|
trailing = true;
|
||||||
|
|
||||||
|
if (isObject(options)) {
|
||||||
|
leading = !!options.leading;
|
||||||
|
maxing = 'maxWait' in options;
|
||||||
|
maxWait = maxing ? Math.max(options.maxWait || 0, wait) : maxWait;
|
||||||
|
trailing = 'trailing' in options ? !!options.trailing : trailing;
|
||||||
|
}
|
||||||
|
|
||||||
|
function invokeFunc(time) {
|
||||||
|
var args = lastArgs,
|
||||||
|
thisArg = lastThis;
|
||||||
|
|
||||||
|
lastArgs = lastThis = undefined;
|
||||||
|
lastInvokeTime = time;
|
||||||
|
result = func.apply(thisArg, args);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function leadingEdge(time) {
|
||||||
|
// Reset any `maxWait` timer.
|
||||||
|
lastInvokeTime = time;
|
||||||
|
// Start the timer for the trailing edge.
|
||||||
|
timerId = setTimeout(timerExpired, wait);
|
||||||
|
// Invoke the leading edge.
|
||||||
|
return leading ? invokeFunc(time) : result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function remainingWait(time) {
|
||||||
|
var timeSinceLastCall = time - lastCallTime,
|
||||||
|
timeSinceLastInvoke = time - lastInvokeTime,
|
||||||
|
timeWaiting = wait - timeSinceLastCall;
|
||||||
|
|
||||||
|
return maxing
|
||||||
|
? Math.min(timeWaiting, maxWait - timeSinceLastInvoke)
|
||||||
|
: timeWaiting;
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldInvoke(time) {
|
||||||
|
var timeSinceLastCall = time - lastCallTime,
|
||||||
|
timeSinceLastInvoke = time - lastInvokeTime;
|
||||||
|
|
||||||
|
// Either this is the first call, activity has stopped and we're at the
|
||||||
|
// trailing edge, the system time has gone backwards and we're treating
|
||||||
|
// it as the trailing edge, or we've hit the `maxWait` limit.
|
||||||
|
return (
|
||||||
|
lastCallTime === undefined ||
|
||||||
|
timeSinceLastCall >= wait ||
|
||||||
|
timeSinceLastCall < 0 ||
|
||||||
|
(maxing && timeSinceLastInvoke >= maxWait)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function timerExpired() {
|
||||||
|
var time = Date.now();
|
||||||
|
if (shouldInvoke(time)) {
|
||||||
|
return trailingEdge(time);
|
||||||
|
}
|
||||||
|
// Restart the timer.
|
||||||
|
timerId = setTimeout(timerExpired, remainingWait(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
function trailingEdge(time) {
|
||||||
|
timerId = undefined;
|
||||||
|
|
||||||
|
// Only invoke if we have `lastArgs` which means `func` has been
|
||||||
|
// debounced at least once.
|
||||||
|
if (trailing && lastArgs) {
|
||||||
|
return invokeFunc(time);
|
||||||
|
}
|
||||||
|
lastArgs = lastThis = undefined;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancel() {
|
||||||
|
if (timerId !== undefined) {
|
||||||
|
clearTimeout(timerId);
|
||||||
|
}
|
||||||
|
lastInvokeTime = 0;
|
||||||
|
lastArgs = lastCallTime = lastThis = timerId = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function flush() {
|
||||||
|
return timerId === undefined ? result : trailingEdge(Date.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
function debounced() {
|
||||||
|
var time = Date.now(),
|
||||||
|
isInvoking = shouldInvoke(time);
|
||||||
|
|
||||||
|
lastArgs = arguments;
|
||||||
|
lastThis = this;
|
||||||
|
lastCallTime = time;
|
||||||
|
|
||||||
|
if (isInvoking) {
|
||||||
|
if (timerId === undefined) {
|
||||||
|
return leadingEdge(lastCallTime);
|
||||||
|
}
|
||||||
|
if (maxing) {
|
||||||
|
// Handle invocations in a tight loop.
|
||||||
|
timerId = setTimeout(timerExpired, wait);
|
||||||
|
return invokeFunc(lastCallTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (timerId === undefined) {
|
||||||
|
timerId = setTimeout(timerExpired, wait);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
debounced.cancel = cancel;
|
||||||
|
debounced.flush = flush;
|
||||||
|
return debounced;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MapCacheType {
|
||||||
|
delete(key: any): boolean;
|
||||||
|
get(key: any): any;
|
||||||
|
has(key: any): boolean;
|
||||||
|
set(key: any, value: any): this;
|
||||||
|
clear?: (() => void) | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
type MemoizedFunction = {
|
||||||
|
cache: MapCacheType;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lodash <https://lodash.com/>
|
||||||
|
* Copyright JS Foundation and other contributors <https://js.foundation/>
|
||||||
|
* Released under MIT license <https://lodash.com/license>
|
||||||
|
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
|
||||||
|
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
||||||
|
*/
|
||||||
|
export function memoize<T extends (...args: any) => any>(
|
||||||
|
func: T
|
||||||
|
): T & MemoizedFunction {
|
||||||
|
const memoized = function () {
|
||||||
|
const args = arguments;
|
||||||
|
const key = args[0];
|
||||||
|
const cache = memoized.cache;
|
||||||
|
|
||||||
|
if (cache.has(key)) {
|
||||||
|
return cache.get(key);
|
||||||
|
}
|
||||||
|
const result = func.apply(this, args);
|
||||||
|
memoized.cache = cache.set(key, result) || cache;
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
memoized.cache = new (memoize.Cache || MapCache)();
|
||||||
|
/* eslint-disable @typescript-eslint/ban-ts-comment*/
|
||||||
|
// @ts-ignore
|
||||||
|
return memoized;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expose `MapCache`.
|
||||||
|
memoize.Cache = MapCache;
|
||||||
|
|
||||||
|
function MapCache(entries?: any) {
|
||||||
|
let index = -1;
|
||||||
|
const length = entries == null ? 0 : entries.length;
|
||||||
|
|
||||||
|
this.clear();
|
||||||
|
while (++index < length) {
|
||||||
|
const entry = entries[index];
|
||||||
|
this.set(entry[0], entry[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapCacheClear() {
|
||||||
|
this.size = 0;
|
||||||
|
this.__data__ = {
|
||||||
|
hash: new Hash(),
|
||||||
|
map: new Map(),
|
||||||
|
string: new Hash(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapCacheDelete(key) {
|
||||||
|
var result = getMapData(this, key)['delete'](key);
|
||||||
|
this.size -= result ? 1 : 0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapCacheGet(key) {
|
||||||
|
return getMapData(this, key).get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapCacheHas(key) {
|
||||||
|
return getMapData(this, key).has(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapCacheSet(key, value) {
|
||||||
|
var data = getMapData(this, key),
|
||||||
|
size = data.size;
|
||||||
|
|
||||||
|
data.set(key, value);
|
||||||
|
this.size += data.size == size ? 0 : 1;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
MapCache.prototype.clear = mapCacheClear;
|
||||||
|
MapCache.prototype['delete'] = mapCacheDelete;
|
||||||
|
MapCache.prototype.get = mapCacheGet;
|
||||||
|
MapCache.prototype.has = mapCacheHas;
|
||||||
|
MapCache.prototype.set = mapCacheSet;
|
||||||
|
|
||||||
|
function Hash(entries?) {
|
||||||
|
var index = -1,
|
||||||
|
length = entries == null ? 0 : entries.length;
|
||||||
|
|
||||||
|
this.clear();
|
||||||
|
while (++index < length) {
|
||||||
|
var entry = entries[index];
|
||||||
|
this.set(entry[0], entry[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const HASH_UNDEFINED = '__lodash_hash_undefined__';
|
||||||
|
|
||||||
|
function hashClear() {
|
||||||
|
this.__data__ = Object.create ? Object.create(null) : {};
|
||||||
|
this.size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hashDelete(key) {
|
||||||
|
var result = this.has(key) && delete this.__data__[key];
|
||||||
|
this.size -= result ? 1 : 0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hashGet(key) {
|
||||||
|
var data = this.__data__;
|
||||||
|
if (Object.create) {
|
||||||
|
var result = data[key];
|
||||||
|
return result === HASH_UNDEFINED ? undefined : result;
|
||||||
|
}
|
||||||
|
return Object.hasOwnProperty.call(data, key) ? data[key] : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hashHas(key) {
|
||||||
|
var data = this.__data__;
|
||||||
|
return Object.create
|
||||||
|
? data[key] !== undefined
|
||||||
|
: Object.hasOwnProperty.call(data, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
function hashSet(key, value) {
|
||||||
|
var data = this.__data__;
|
||||||
|
this.size += this.has(key) ? 0 : 1;
|
||||||
|
data[key] = Object.create && value === undefined ? HASH_UNDEFINED : value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add methods to `Hash`.
|
||||||
|
Hash.prototype.clear = hashClear;
|
||||||
|
Hash.prototype['delete'] = hashDelete;
|
||||||
|
Hash.prototype.get = hashGet;
|
||||||
|
Hash.prototype.has = hashHas;
|
||||||
|
Hash.prototype.set = hashSet;
|
||||||
|
|
||||||
|
function getMapData(map, key) {
|
||||||
|
var data = map.__data__;
|
||||||
|
return isKeyable(key)
|
||||||
|
? data[typeof key == 'string' ? 'string' : 'hash']
|
||||||
|
: data.map;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isKeyable(value) {
|
||||||
|
var type = typeof value;
|
||||||
|
return type == 'string' ||
|
||||||
|
type == 'number' ||
|
||||||
|
type == 'symbol' ||
|
||||||
|
type == 'boolean'
|
||||||
|
? value !== '__proto__'
|
||||||
|
: value === null;
|
||||||
|
}
|
|
@ -19,7 +19,7 @@ import styled from 'styled-components';
|
||||||
import Popover from 'design/Popover';
|
import Popover from 'design/Popover';
|
||||||
import theme from 'design/theme';
|
import theme from 'design/theme';
|
||||||
import { Box } from 'design';
|
import { Box } from 'design';
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'shared/utils/highbar';
|
||||||
|
|
||||||
export default function JoinedUsers(props) {
|
export default function JoinedUsers(props) {
|
||||||
const { active, users, open = false, ml, mr } = props;
|
const { active, users, open = false, ml, mr } = props;
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
import React, { useState, useEffect, useRef } from 'react';
|
import React, { useState, useEffect, useRef } from 'react';
|
||||||
|
|
||||||
import { throttle } from 'lodash';
|
import { throttle } from 'shared/utils/highbar';
|
||||||
import { dateToUtc } from 'shared/services/loc';
|
import { dateToUtc } from 'shared/services/loc';
|
||||||
import { format } from 'date-fns';
|
import { format } from 'date-fns';
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { throttle } from 'lodash';
|
import { throttle } from 'shared/utils/highbar';
|
||||||
|
|
||||||
import TtyPlayer from 'teleport/lib/term/ttyPlayer';
|
import TtyPlayer from 'teleport/lib/term/ttyPlayer';
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { throttle } from 'lodash';
|
import { throttle } from 'shared/utils/highbar';
|
||||||
|
|
||||||
export default function useTtyBpfMapper(tty, events) {
|
export default function useTtyBpfMapper(tty, events) {
|
||||||
// create a map [time][index] for quick lookups
|
// create a map [time][index] for quick lookups
|
||||||
|
|
|
@ -15,7 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { throttle } from 'lodash';
|
import { throttle } from 'shared/utils/highbar';
|
||||||
import Logger from 'shared/libs/logger';
|
import Logger from 'shared/libs/logger';
|
||||||
|
|
||||||
import session from 'teleport/services/websession';
|
import session from 'teleport/services/websession';
|
||||||
|
|
|
@ -15,7 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'shared/utils/highbar';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { height, space, color } from 'design/system';
|
import { height, space, color } from 'design/system';
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { generatePath } from 'react-router';
|
import { generatePath } from 'react-router';
|
||||||
import { merge } from 'lodash';
|
import { mergeDeep } from 'shared/utils/highbar';
|
||||||
|
|
||||||
import generateResourcePath from './generateResourcePath';
|
import generateResourcePath from './generateResourcePath';
|
||||||
|
|
||||||
|
@ -554,7 +554,7 @@ const cfg = {
|
||||||
},
|
},
|
||||||
|
|
||||||
init(backendConfig = {}) {
|
init(backendConfig = {}) {
|
||||||
merge(this, backendConfig);
|
mergeDeep(this, backendConfig);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -16,12 +16,14 @@ limitations under the License.
|
||||||
import 'xterm/css/xterm.css';
|
import 'xterm/css/xterm.css';
|
||||||
import { Terminal } from 'xterm';
|
import { Terminal } from 'xterm';
|
||||||
import { FitAddon } from 'xterm-addon-fit';
|
import { FitAddon } from 'xterm-addon-fit';
|
||||||
import { debounce, Cancelable, isInteger } from 'lodash';
|
import { debounce, isInteger } from 'shared/utils/highbar';
|
||||||
import Logger from 'shared/libs/logger';
|
import Logger from 'shared/libs/logger';
|
||||||
|
|
||||||
import { TermEvent } from './enums';
|
import { TermEvent } from './enums';
|
||||||
import Tty from './tty';
|
import Tty from './tty';
|
||||||
|
|
||||||
|
import type { DebouncedFunc } from 'shared/utils/highbar';
|
||||||
|
|
||||||
const logger = Logger.create('lib/term/terminal');
|
const logger = Logger.create('lib/term/terminal');
|
||||||
const DISCONNECT_TXT = 'disconnected';
|
const DISCONNECT_TXT = 'disconnected';
|
||||||
const WINDOW_RESIZE_DEBOUNCE_DELAY = 200;
|
const WINDOW_RESIZE_DEBOUNCE_DELAY = 200;
|
||||||
|
@ -37,7 +39,7 @@ export default class TtyTerminal {
|
||||||
_scrollBack: number;
|
_scrollBack: number;
|
||||||
_fontFamily: string;
|
_fontFamily: string;
|
||||||
_fontSize: number;
|
_fontSize: number;
|
||||||
_debouncedResize: (() => void) & Cancelable;
|
_debouncedResize: DebouncedFunc<() => void>;
|
||||||
_fitAddon = new FitAddon();
|
_fitAddon = new FitAddon();
|
||||||
|
|
||||||
constructor(tty: Tty, options: Options) {
|
constructor(tty: Tty, options: Options) {
|
||||||
|
|
|
@ -14,8 +14,6 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { map } from 'lodash';
|
|
||||||
|
|
||||||
import api from 'teleport/services/api';
|
import api from 'teleport/services/api';
|
||||||
import cfg from 'teleport/config';
|
import cfg from 'teleport/config';
|
||||||
|
|
||||||
|
@ -26,7 +24,7 @@ const service = {
|
||||||
fetchSessions(clusterId) {
|
fetchSessions(clusterId) {
|
||||||
return api.get(cfg.getTerminalSessionUrl({ clusterId })).then(response => {
|
return api.get(cfg.getTerminalSessionUrl({ clusterId })).then(response => {
|
||||||
if (response && response.sessions) {
|
if (response && response.sessions) {
|
||||||
return map(response.sessions, makeSession);
|
return response.sessions.map(makeSession);
|
||||||
}
|
}
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
|
@ -44,7 +42,7 @@ const service = {
|
||||||
|
|
||||||
const parties: ParticipantList = {};
|
const parties: ParticipantList = {};
|
||||||
json.sessions.forEach(s => {
|
json.sessions.forEach(s => {
|
||||||
parties[s.id] = map(s.parties, makeParticipant);
|
parties[s.id] = s.parties.map(makeParticipant);
|
||||||
});
|
});
|
||||||
|
|
||||||
return parties;
|
return parties;
|
||||||
|
|
|
@ -14,12 +14,10 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { at } from 'lodash';
|
|
||||||
|
|
||||||
import { ResetToken } from './types';
|
import { ResetToken } from './types';
|
||||||
|
|
||||||
export default function makeResetToken(json): ResetToken {
|
export default function makeResetToken(json): ResetToken {
|
||||||
const [expires, username, value] = at(json, ['expiry', 'user', 'tokenId']);
|
const { expires, username, value } = json;
|
||||||
return {
|
return {
|
||||||
username,
|
username,
|
||||||
expires: new Date(expires),
|
expires: new Date(expires),
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
import fs, { existsSync, readFileSync, writeFileSync } from 'fs';
|
import fs, { existsSync, readFileSync, writeFileSync } from 'fs';
|
||||||
|
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'shared/utils/highbar';
|
||||||
|
|
||||||
import Logger from 'teleterm/logger';
|
import Logger from 'teleterm/logger';
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ import winston, {
|
||||||
format,
|
format,
|
||||||
transports,
|
transports,
|
||||||
} from 'winston';
|
} from 'winston';
|
||||||
import { isObject } from 'lodash';
|
import { isObject } from 'shared/utils/highbar';
|
||||||
|
|
||||||
import split2 from 'split2';
|
import split2 from 'split2';
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
|
|
||||||
import { spawn } from 'child_process';
|
import { spawn } from 'child_process';
|
||||||
|
|
||||||
import { memoize } from 'lodash';
|
import { memoize } from 'shared/utils/highbar';
|
||||||
|
|
||||||
import Logger from 'teleterm/logger';
|
import Logger from 'teleterm/logger';
|
||||||
import { unique } from 'teleterm/ui/utils/uid';
|
import { unique } from 'teleterm/ui/utils/uid';
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as grpc from '@grpc/grpc-js';
|
import * as grpc from '@grpc/grpc-js';
|
||||||
import { isObject, transform } from 'lodash';
|
import { isObject } from 'shared/utils/highbar';
|
||||||
|
|
||||||
import Logger from 'teleterm/logger';
|
import Logger from 'teleterm/logger';
|
||||||
|
|
||||||
|
@ -127,24 +127,24 @@ export const withLogging = (logger: Logger): UnaryInterceptor => {
|
||||||
};
|
};
|
||||||
|
|
||||||
function filterSensitiveProperties(toFilter: object): object {
|
function filterSensitiveProperties(toFilter: object): object {
|
||||||
return transform(
|
const acc = {};
|
||||||
toFilter,
|
const transformer = (result: object, value: any, key: any) => {
|
||||||
(result: object, value: any, key: any) => {
|
if (
|
||||||
if (
|
SENSITIVE_PROPERTIES.some(
|
||||||
SENSITIVE_PROPERTIES.some(
|
sensitiveProp => typeof key === 'string' && key.includes(sensitiveProp)
|
||||||
sensitiveProp =>
|
)
|
||||||
typeof key === 'string' && key.includes(sensitiveProp)
|
) {
|
||||||
)
|
result[key] = '~FILTERED~';
|
||||||
) {
|
return;
|
||||||
result[key] = '~FILTERED~';
|
}
|
||||||
return;
|
if (isObject(value)) {
|
||||||
}
|
result[key] = filterSensitiveProperties(value);
|
||||||
if (isObject(value)) {
|
return;
|
||||||
result[key] = filterSensitiveProperties(value);
|
}
|
||||||
return;
|
result[key] = value;
|
||||||
}
|
};
|
||||||
result[key] = value;
|
|
||||||
},
|
Object.keys(toFilter).forEach(key => transformer(acc, toFilter[key], key));
|
||||||
{}
|
|
||||||
);
|
return acc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'shared/utils/highbar';
|
||||||
import { space, width, color, height } from 'styled-system';
|
import { space, width, color, height } from 'styled-system';
|
||||||
|
|
||||||
export default function ClusterSearch(props: Props) {
|
export default function ClusterSearch(props: Props) {
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useMemo, useRef } from 'react';
|
import React, { useMemo, useRef } from 'react';
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'shared/utils/highbar';
|
||||||
import { Box, ButtonSecondary, Flex, Link, Text } from 'design';
|
import { Box, ButtonSecondary, Flex, Link, Text } from 'design';
|
||||||
import Validation from 'shared/components/Validation';
|
import Validation from 'shared/components/Validation';
|
||||||
import * as Alerts from 'design/Alert';
|
import * as Alerts from 'design/Alert';
|
||||||
|
|
|
@ -14,10 +14,10 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { debounce } from 'lodash';
|
|
||||||
import React, { useEffect, useRef } from 'react';
|
import React, { useEffect, useRef } from 'react';
|
||||||
import styled, { useTheme } from 'styled-components';
|
import styled, { useTheme } from 'styled-components';
|
||||||
import { Box, Flex } from 'design';
|
import { Box, Flex } from 'design';
|
||||||
|
import { debounce } from 'shared/utils/highbar';
|
||||||
|
|
||||||
import { IPtyProcess } from 'teleterm/sharedProcess/ptyHost';
|
import { IPtyProcess } from 'teleterm/sharedProcess/ptyHost';
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
||||||
import 'xterm/css/xterm.css';
|
import 'xterm/css/xterm.css';
|
||||||
import { IDisposable, Terminal } from 'xterm';
|
import { IDisposable, Terminal } from 'xterm';
|
||||||
import { FitAddon } from 'xterm-addon-fit';
|
import { FitAddon } from 'xterm-addon-fit';
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'shared/utils/highbar';
|
||||||
|
|
||||||
import { IPtyProcess } from 'teleterm/sharedProcess/ptyHost';
|
import { IPtyProcess } from 'teleterm/sharedProcess/ptyHost';
|
||||||
import Logger from 'teleterm/logger';
|
import Logger from 'teleterm/logger';
|
||||||
|
|
|
@ -18,7 +18,7 @@ import { useEffect } from 'react';
|
||||||
|
|
||||||
import { useAsync } from 'shared/hooks/useAsync';
|
import { useAsync } from 'shared/hooks/useAsync';
|
||||||
|
|
||||||
import { once } from 'lodash';
|
import { runOnce } from 'shared/utils/highbar';
|
||||||
|
|
||||||
import { useAppContext } from 'teleterm/ui/appContextProvider';
|
import { useAppContext } from 'teleterm/ui/appContextProvider';
|
||||||
import { IAppContext } from 'teleterm/ui/types';
|
import { IAppContext } from 'teleterm/ui/types';
|
||||||
|
@ -131,7 +131,7 @@ async function initState(
|
||||||
removeInitCommand();
|
removeInitCommand();
|
||||||
});
|
});
|
||||||
|
|
||||||
const markDocumentAsConnectedOnce = once(() => {
|
const markDocumentAsConnectedOnce = runOnce(() => {
|
||||||
docsService.update(doc.uri, { status: 'connected' });
|
docsService.update(doc.uri, { status: 'connected' });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'shared/utils/highbar';
|
||||||
import { Box, Flex } from 'design';
|
import { Box, Flex } from 'design';
|
||||||
import { color, height, space, width } from 'styled-system';
|
import { color, height, space, width } from 'styled-system';
|
||||||
import { Spinner } from 'design/Icon';
|
import { Spinner } from 'design/Icon';
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { Fragment, useMemo, useState } from 'react';
|
import React, { Fragment, useMemo, useState } from 'react';
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'shared/utils/highbar';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
import { prepareVirtualScrollItems } from './prepareVirtualScrollItems';
|
import { prepareVirtualScrollItems } from './prepareVirtualScrollItems';
|
||||||
|
|
|
@ -85,7 +85,7 @@ describe('restoring workspace', () => {
|
||||||
return { workspacesService, clusterDocument };
|
return { workspacesService, clusterDocument };
|
||||||
}
|
}
|
||||||
|
|
||||||
it('restores the workspace if it there is a persisted state for given clusterUri', () => {
|
it('restores the workspace if there is a persisted state for given clusterUri', () => {
|
||||||
const testClusterUri = '/clusters/test-uri';
|
const testClusterUri = '/clusters/test-uri';
|
||||||
const testWorkspace: Workspace = {
|
const testWorkspace: Workspace = {
|
||||||
accessRequests: {
|
accessRequests: {
|
||||||
|
|
|
@ -15,8 +15,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useStore } from 'shared/libs/stores';
|
import { useStore } from 'shared/libs/stores';
|
||||||
|
import { arrayObjectIsEqual } from 'shared/utils/highbar';
|
||||||
|
|
||||||
import { isEqual } from 'lodash';
|
|
||||||
/* eslint-disable @typescript-eslint/ban-ts-comment*/
|
/* eslint-disable @typescript-eslint/ban-ts-comment*/
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { ResourceKind } from 'e-teleport/Workflow/NewRequest/useNewRequest';
|
import { ResourceKind } from 'e-teleport/Workflow/NewRequest/useNewRequest';
|
||||||
|
@ -344,7 +344,7 @@ export class WorkspacesService extends ImmutableStore<WorkspacesState> {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
previousDocuments?.length &&
|
previousDocuments?.length &&
|
||||||
!isEqual(
|
!arrayObjectIsEqual(
|
||||||
omitUriAndTitle(previousDocuments),
|
omitUriAndTitle(previousDocuments),
|
||||||
omitUriAndTitle(currentDocuments)
|
omitUriAndTitle(currentDocuments)
|
||||||
)
|
)
|
||||||
|
|
56
yarn.lock
56
yarn.lock
|
@ -202,13 +202,6 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types" "^7.16.0"
|
"@babel/types" "^7.16.0"
|
||||||
|
|
||||||
"@babel/helper-module-imports@^7.0.0-beta.49":
|
|
||||||
version "7.18.6"
|
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e"
|
|
||||||
integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==
|
|
||||||
dependencies:
|
|
||||||
"@babel/types" "^7.18.6"
|
|
||||||
|
|
||||||
"@babel/helper-module-transforms@^7.12.1", "@babel/helper-module-transforms@^7.16.0":
|
"@babel/helper-module-transforms@^7.12.1", "@babel/helper-module-transforms@^7.16.0":
|
||||||
version "7.16.0"
|
version "7.16.0"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.16.0.tgz#1c82a8dd4cb34577502ebd2909699b194c3e9bb5"
|
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.16.0.tgz#1c82a8dd4cb34577502ebd2909699b194c3e9bb5"
|
||||||
|
@ -280,11 +273,6 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types" "^7.16.0"
|
"@babel/types" "^7.16.0"
|
||||||
|
|
||||||
"@babel/helper-string-parser@^7.19.4":
|
|
||||||
version "7.19.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63"
|
|
||||||
integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==
|
|
||||||
|
|
||||||
"@babel/helper-validator-identifier@^7.15.7":
|
"@babel/helper-validator-identifier@^7.15.7":
|
||||||
version "7.15.7"
|
version "7.15.7"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389"
|
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389"
|
||||||
|
@ -295,11 +283,6 @@
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz#9c97e30d31b2b8c72a1d08984f2ca9b574d7a076"
|
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz#9c97e30d31b2b8c72a1d08984f2ca9b574d7a076"
|
||||||
integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==
|
integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==
|
||||||
|
|
||||||
"@babel/helper-validator-identifier@^7.19.1":
|
|
||||||
version "7.19.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2"
|
|
||||||
integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==
|
|
||||||
|
|
||||||
"@babel/helper-validator-option@^7.14.5":
|
"@babel/helper-validator-option@^7.14.5":
|
||||||
version "7.14.5"
|
version "7.14.5"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3"
|
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3"
|
||||||
|
@ -1155,15 +1138,6 @@
|
||||||
"@babel/helper-validator-identifier" "^7.15.7"
|
"@babel/helper-validator-identifier" "^7.15.7"
|
||||||
to-fast-properties "^2.0.0"
|
to-fast-properties "^2.0.0"
|
||||||
|
|
||||||
"@babel/types@^7.0.0-beta.49", "@babel/types@^7.18.6":
|
|
||||||
version "7.19.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.19.4.tgz#0dd5c91c573a202d600490a35b33246fed8a41c7"
|
|
||||||
integrity sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==
|
|
||||||
dependencies:
|
|
||||||
"@babel/helper-string-parser" "^7.19.4"
|
|
||||||
"@babel/helper-validator-identifier" "^7.19.1"
|
|
||||||
to-fast-properties "^2.0.0"
|
|
||||||
|
|
||||||
"@bcoe/v8-coverage@^0.2.3":
|
"@bcoe/v8-coverage@^0.2.3":
|
||||||
version "0.2.3"
|
version "0.2.3"
|
||||||
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
||||||
|
@ -3118,11 +3092,6 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
keyv "*"
|
keyv "*"
|
||||||
|
|
||||||
"@types/lodash@4.14.149":
|
|
||||||
version "4.14.149"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.149.tgz#1342d63d948c6062838fbf961012f74d4e638440"
|
|
||||||
integrity sha512-ijGqzZt/b7BfzcK9vTrS6MFljQRPn5BFWOx8oE0GYxribu6uV+aA9zZuXI1zc/etK9E8nrgdoF2+LgUw7+9tJQ==
|
|
||||||
|
|
||||||
"@types/long@^4.0.1":
|
"@types/long@^4.0.1":
|
||||||
version "4.0.2"
|
version "4.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a"
|
resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a"
|
||||||
|
@ -4532,17 +4501,6 @@ babel-plugin-jest-hoist@^27.4.0:
|
||||||
"@types/babel__core" "^7.0.0"
|
"@types/babel__core" "^7.0.0"
|
||||||
"@types/babel__traverse" "^7.0.6"
|
"@types/babel__traverse" "^7.0.6"
|
||||||
|
|
||||||
babel-plugin-lodash@^3.3.4:
|
|
||||||
version "3.3.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/babel-plugin-lodash/-/babel-plugin-lodash-3.3.4.tgz#4f6844358a1340baed182adbeffa8df9967bc196"
|
|
||||||
integrity sha512-yDZLjK7TCkWl1gpBeBGmuaDIFhZKmkoL+Cu2MUUjv5VxUZx/z7tBGBCBcQs5RI1Bkz5LLmNdjx7paOyQtMovyg==
|
|
||||||
dependencies:
|
|
||||||
"@babel/helper-module-imports" "^7.0.0-beta.49"
|
|
||||||
"@babel/types" "^7.0.0-beta.49"
|
|
||||||
glob "^7.1.1"
|
|
||||||
lodash "^4.17.10"
|
|
||||||
require-package-name "^2.0.1"
|
|
||||||
|
|
||||||
babel-plugin-macros@^2.0.0, babel-plugin-macros@^2.8.0:
|
babel-plugin-macros@^2.0.0, babel-plugin-macros@^2.8.0:
|
||||||
version "2.8.0"
|
version "2.8.0"
|
||||||
resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138"
|
resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138"
|
||||||
|
@ -10424,13 +10382,6 @@ locate-path@^6.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
p-locate "^5.0.0"
|
p-locate "^5.0.0"
|
||||||
|
|
||||||
lodash-webpack-plugin@^0.11.6:
|
|
||||||
version "0.11.6"
|
|
||||||
resolved "https://registry.yarnpkg.com/lodash-webpack-plugin/-/lodash-webpack-plugin-0.11.6.tgz#8204c6b78beb62ce5211217dfe783c21557ecd33"
|
|
||||||
integrity sha512-nsHN/+IxZK/C425vGC8pAxkKJ8KQH2+NJnhDul14zYNWr6HJcA95w+oRR7Cp0oZpOdMplDZXmjVROp8prPk7ig==
|
|
||||||
dependencies:
|
|
||||||
lodash "^4.17.20"
|
|
||||||
|
|
||||||
lodash.camelcase@^4.3.0:
|
lodash.camelcase@^4.3.0:
|
||||||
version "4.3.0"
|
version "4.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
|
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
|
||||||
|
@ -10451,7 +10402,7 @@ lodash.uniq@4.5.0:
|
||||||
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
|
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
|
||||||
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
|
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
|
||||||
|
|
||||||
lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0:
|
lodash@^4.17.11, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0:
|
||||||
version "4.17.21"
|
version "4.17.21"
|
||||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
||||||
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
||||||
|
@ -13113,11 +13064,6 @@ require-in-the-middle@^5.0.3:
|
||||||
module-details-from-path "^1.0.3"
|
module-details-from-path "^1.0.3"
|
||||||
resolve "^1.22.1"
|
resolve "^1.22.1"
|
||||||
|
|
||||||
require-package-name@^2.0.1:
|
|
||||||
version "2.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/require-package-name/-/require-package-name-2.0.1.tgz#c11e97276b65b8e2923f75dabf5fb2ef0c3841b9"
|
|
||||||
integrity sha512-uuoJ1hU/k6M0779t3VMVIYpb2VMJk05cehCaABFhXaibcbvfgR8wKiozLjVFSzJPmQMRqIcO0HMyTFqfV09V6Q==
|
|
||||||
|
|
||||||
requireindex@^1.2.0:
|
requireindex@^1.2.0:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/requireindex/-/requireindex-1.2.0.tgz#3463cdb22ee151902635aa6c9535d4de9c2ef1ef"
|
resolved "https://registry.yarnpkg.com/requireindex/-/requireindex-1.2.0.tgz#3463cdb22ee151902635aa6c9535d4de9c2ef1ef"
|
||||||
|
|
Loading…
Reference in a new issue