1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Generic logs view with Pod selector (#1984)

* Adding LogTabStore

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Adding Pod selector in logs tab

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Refresh containers on pod change

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Adding <LogResourceSelector /> tests

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Adding LogTabStore tests

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Clearn getPodsByOwnerId method

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Extracting dummy pods into mock file

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Eliminating containers and initContainers from store

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Refreshing tab pods if pod amount is changed in store

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* A bit of cleaning up, fixing tests

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Fix lint newline errors

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Return getPodsByOwner() method

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Rename log tab when pod changes

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>
This commit is contained in:
Alex Andreev 2021-01-27 17:20:02 +03:00 committed by GitHub
parent 724c6c3265
commit a157eb03e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 1359 additions and 135 deletions

View File

@ -626,7 +626,644 @@
}, },
"@k8slens/extensions": { "@k8slens/extensions": {
"version": "file:../../src/extensions/npm/extensions", "version": "file:../../src/extensions/npm/extensions",
"dev": true "dev": true,
"requires": {
"@material-ui/core": "*",
"@types/node": "*",
"@types/react-select": "*",
"conf": "^7.0.1"
},
"dependencies": {
"@babel/runtime": {
"version": "7.12.5",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.5.tgz",
"integrity": "sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==",
"dev": true,
"requires": {
"regenerator-runtime": "^0.13.4"
}
},
"@emotion/hash": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz",
"integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==",
"dev": true
},
"@material-ui/core": {
"version": "4.11.2",
"resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.11.2.tgz",
"integrity": "sha512-/D1+AQQeYX/WhT/FUk78UCRj8ch/RCglsQLYujYTIqPSJlwZHKcvHidNeVhODXeApojeXjkl0tWdk5C9ofwOkQ==",
"dev": true,
"requires": {
"@babel/runtime": "^7.4.4",
"@material-ui/styles": "^4.11.2",
"@material-ui/system": "^4.11.2",
"@material-ui/types": "^5.1.0",
"@material-ui/utils": "^4.11.2",
"@types/react-transition-group": "^4.2.0",
"clsx": "^1.0.4",
"hoist-non-react-statics": "^3.3.2",
"popper.js": "1.16.1-lts",
"prop-types": "^15.7.2",
"react-is": "^16.8.0 || ^17.0.0",
"react-transition-group": "^4.4.0"
}
},
"@material-ui/styles": {
"version": "4.11.2",
"resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.2.tgz",
"integrity": "sha512-xbItf8zkfD3FuGoD9f2vlcyPf9jTEtj9YTJoNNV+NMWaSAHXgrW6geqRoo/IwBuMjqpwqsZhct13e2nUyU9Ljw==",
"dev": true,
"requires": {
"@babel/runtime": "^7.4.4",
"@emotion/hash": "^0.8.0",
"@material-ui/types": "^5.1.0",
"@material-ui/utils": "^4.11.2",
"clsx": "^1.0.4",
"csstype": "^2.5.2",
"hoist-non-react-statics": "^3.3.2",
"jss": "^10.0.3",
"jss-plugin-camel-case": "^10.0.3",
"jss-plugin-default-unit": "^10.0.3",
"jss-plugin-global": "^10.0.3",
"jss-plugin-nested": "^10.0.3",
"jss-plugin-props-sort": "^10.0.3",
"jss-plugin-rule-value-function": "^10.0.3",
"jss-plugin-vendor-prefixer": "^10.0.3",
"prop-types": "^15.7.2"
}
},
"@material-ui/system": {
"version": "4.11.2",
"resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.11.2.tgz",
"integrity": "sha512-BELFJEel5E+5DMiZb6XXT3peWRn6UixRvBtKwSxqntmD0+zwbbfCij6jtGwwdJhN1qX/aXrKu10zX31GBaeR7A==",
"dev": true,
"requires": {
"@babel/runtime": "^7.4.4",
"@material-ui/utils": "^4.11.2",
"csstype": "^2.5.2",
"prop-types": "^15.7.2"
}
},
"@material-ui/types": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz",
"integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==",
"dev": true
},
"@material-ui/utils": {
"version": "4.11.2",
"resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.2.tgz",
"integrity": "sha512-Uul8w38u+PICe2Fg2pDKCaIG7kOyhowZ9vjiC1FsVwPABTW8vPPKfF6OvxRq3IiBaI1faOJmgdvMG7rMJARBhA==",
"dev": true,
"requires": {
"@babel/runtime": "^7.4.4",
"prop-types": "^15.7.2",
"react-is": "^16.8.0 || ^17.0.0"
}
},
"@types/node": {
"version": "14.14.21",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.21.tgz",
"integrity": "sha512-cHYfKsnwllYhjOzuC5q1VpguABBeecUp24yFluHpn/BQaVxB1CuQ1FSRZCzrPxrkIfWISXV2LbeoBthLWg0+0A==",
"dev": true
},
"@types/prop-types": {
"version": "15.7.3",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
"integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==",
"dev": true
},
"@types/react": {
"version": "17.0.0",
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.0.tgz",
"integrity": "sha512-aj/L7RIMsRlWML3YB6KZiXB3fV2t41+5RBGYF8z+tAKU43Px8C3cYUZsDvf1/+Bm4FK21QWBrDutu8ZJ/70qOw==",
"dev": true,
"requires": {
"@types/prop-types": "*",
"csstype": "^3.0.2"
},
"dependencies": {
"csstype": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.6.tgz",
"integrity": "sha512-+ZAmfyWMT7TiIlzdqJgjMb7S4f1beorDbWbsocyK4RaiqA5RTX3K14bnBWmmA9QEM0gRdsjyyrEmcyga8Zsxmw==",
"dev": true
}
}
},
"@types/react-dom": {
"version": "17.0.0",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.0.tgz",
"integrity": "sha512-lUqY7OlkF/RbNtD5nIq7ot8NquXrdFrjSOR6+w9a9RFQevGi1oZO1dcJbXMeONAPKtZ2UrZOEJ5UOCVsxbLk/g==",
"dev": true,
"requires": {
"@types/react": "*"
}
},
"@types/react-select": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@types/react-select/-/react-select-3.1.2.tgz",
"integrity": "sha512-ygvR/2FL87R2OLObEWFootYzkvm67LRA+URYEAcBuvKk7IXmdsnIwSGm60cVXGaqkJQHozb2Cy1t94tCYb6rJA==",
"dev": true,
"requires": {
"@types/react": "*",
"@types/react-dom": "*",
"@types/react-transition-group": "*"
}
},
"@types/react-transition-group": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.0.tgz",
"integrity": "sha512-/QfLHGpu+2fQOqQaXh8MG9q03bFENooTb/it4jr5kKaZlDQfWvjqWZg48AwzPVMBHlRuTRAY7hRHCEOXz5kV6w==",
"dev": true,
"requires": {
"@types/react": "*"
}
},
"ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
"requires": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
}
},
"atomically": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/atomically/-/atomically-1.7.0.tgz",
"integrity": "sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w==",
"dev": true
},
"clsx": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz",
"integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==",
"dev": true
},
"conf": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/conf/-/conf-7.1.2.tgz",
"integrity": "sha512-r8/HEoWPFn4CztjhMJaWNAe5n+gPUCSaJ0oufbqDLFKsA1V8JjAG7G+p0pgoDFAws9Bpk2VtVLLXqOBA7WxLeg==",
"dev": true,
"requires": {
"ajv": "^6.12.2",
"atomically": "^1.3.1",
"debounce-fn": "^4.0.0",
"dot-prop": "^5.2.0",
"env-paths": "^2.2.0",
"json-schema-typed": "^7.0.3",
"make-dir": "^3.1.0",
"onetime": "^5.1.0",
"pkg-up": "^3.1.0",
"semver": "^7.3.2"
}
},
"css-vendor": {
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz",
"integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==",
"dev": true,
"requires": {
"@babel/runtime": "^7.8.3",
"is-in-browser": "^1.0.2"
}
},
"csstype": {
"version": "2.6.14",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.14.tgz",
"integrity": "sha512-2mSc+VEpGPblzAxyeR+vZhJKgYg0Og0nnRi7pmRXFYYxSfnOnW8A5wwQb4n4cE2nIOzqKOAzLCaEX6aBmNEv8A==",
"dev": true
},
"debounce-fn": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/debounce-fn/-/debounce-fn-4.0.0.tgz",
"integrity": "sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ==",
"dev": true,
"requires": {
"mimic-fn": "^3.0.0"
}
},
"dom-helpers": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.0.tgz",
"integrity": "sha512-Ru5o9+V8CpunKnz5LGgWXkmrH/20cGKwcHwS4m73zIvs54CN9epEmT/HLqFJW3kXpakAFkEdzgy1hzlJe3E4OQ==",
"dev": true,
"requires": {
"@babel/runtime": "^7.8.7",
"csstype": "^3.0.2"
},
"dependencies": {
"csstype": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.6.tgz",
"integrity": "sha512-+ZAmfyWMT7TiIlzdqJgjMb7S4f1beorDbWbsocyK4RaiqA5RTX3K14bnBWmmA9QEM0gRdsjyyrEmcyga8Zsxmw==",
"dev": true
}
}
},
"dot-prop": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
"integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==",
"dev": true,
"requires": {
"is-obj": "^2.0.0"
}
},
"env-paths": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.0.tgz",
"integrity": "sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA==",
"dev": true
},
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
},
"fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
"dev": true
},
"find-up": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
"dev": true,
"requires": {
"locate-path": "^3.0.0"
}
},
"hoist-non-react-statics": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
"integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
"dev": true,
"requires": {
"react-is": "^16.7.0"
},
"dependencies": {
"react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
"dev": true
}
}
},
"hyphenate-style-name": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz",
"integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==",
"dev": true
},
"indefinite-observable": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/indefinite-observable/-/indefinite-observable-2.0.1.tgz",
"integrity": "sha512-G8vgmork+6H9S8lUAg1gtXEj2JxIQTo0g2PbFiYOdjkziSI0F7UYBiVwhZRuixhBCNGczAls34+5HJPyZysvxQ==",
"dev": true,
"requires": {
"symbol-observable": "1.2.0"
}
},
"is-in-browser": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz",
"integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU=",
"dev": true
},
"is-obj": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
"integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
"dev": true
},
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"dev": true
},
"json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true
},
"json-schema-typed": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-7.0.3.tgz",
"integrity": "sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A==",
"dev": true
},
"jss": {
"version": "10.5.0",
"resolved": "https://registry.npmjs.org/jss/-/jss-10.5.0.tgz",
"integrity": "sha512-B6151NvG+thUg3murLNHRPLxTLwQ13ep4SH5brj4d8qKtogOx/jupnpfkPGSHPqvcwKJaCLctpj2lEk+5yGwMw==",
"dev": true,
"requires": {
"@babel/runtime": "^7.3.1",
"csstype": "^3.0.2",
"indefinite-observable": "^2.0.1",
"is-in-browser": "^1.1.3",
"tiny-warning": "^1.0.2"
},
"dependencies": {
"csstype": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.6.tgz",
"integrity": "sha512-+ZAmfyWMT7TiIlzdqJgjMb7S4f1beorDbWbsocyK4RaiqA5RTX3K14bnBWmmA9QEM0gRdsjyyrEmcyga8Zsxmw==",
"dev": true
}
}
},
"jss-plugin-camel-case": {
"version": "10.5.0",
"resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.5.0.tgz",
"integrity": "sha512-GSjPL0adGAkuoqeYiXTgO7PlIrmjv5v8lA6TTBdfxbNYpxADOdGKJgIEkffhlyuIZHlPuuiFYTwUreLUmSn7rg==",
"dev": true,
"requires": {
"@babel/runtime": "^7.3.1",
"hyphenate-style-name": "^1.0.3",
"jss": "10.5.0"
}
},
"jss-plugin-default-unit": {
"version": "10.5.0",
"resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.5.0.tgz",
"integrity": "sha512-rsbTtZGCMrbcb9beiDd+TwL991NGmsAgVYH0hATrYJtue9e+LH/Gn4yFD1ENwE+3JzF3A+rPnM2JuD9L/SIIWw==",
"dev": true,
"requires": {
"@babel/runtime": "^7.3.1",
"jss": "10.5.0"
}
},
"jss-plugin-global": {
"version": "10.5.0",
"resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.5.0.tgz",
"integrity": "sha512-FZd9+JE/3D7HMefEG54fEC0XiQ9rhGtDHAT/ols24y8sKQ1D5KIw6OyXEmIdKFmACgxZV2ARQ5pAUypxkk2IFQ==",
"dev": true,
"requires": {
"@babel/runtime": "^7.3.1",
"jss": "10.5.0"
}
},
"jss-plugin-nested": {
"version": "10.5.0",
"resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.5.0.tgz",
"integrity": "sha512-ejPlCLNlEGgx8jmMiDk/zarsCZk+DV0YqXfddpgzbO9Toamo0HweCFuwJ3ZO40UFOfqKwfpKMVH/3HUXgxkTMg==",
"dev": true,
"requires": {
"@babel/runtime": "^7.3.1",
"jss": "10.5.0",
"tiny-warning": "^1.0.2"
}
},
"jss-plugin-props-sort": {
"version": "10.5.0",
"resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.5.0.tgz",
"integrity": "sha512-kTLRvrOetFKz5vM88FAhLNeJIxfjhCepnvq65G7xsAQ/Wgy7HwO1BS/2wE5mx8iLaAWC6Rj5h16mhMk9sKdZxg==",
"dev": true,
"requires": {
"@babel/runtime": "^7.3.1",
"jss": "10.5.0"
}
},
"jss-plugin-rule-value-function": {
"version": "10.5.0",
"resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.5.0.tgz",
"integrity": "sha512-jXINGr8BSsB13JVuK274oEtk0LoooYSJqTBCGeBu2cG/VJ3+4FPs1gwLgsq24xTgKshtZ+WEQMVL34OprLidRA==",
"dev": true,
"requires": {
"@babel/runtime": "^7.3.1",
"jss": "10.5.0",
"tiny-warning": "^1.0.2"
}
},
"jss-plugin-vendor-prefixer": {
"version": "10.5.0",
"resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.5.0.tgz",
"integrity": "sha512-rux3gmfwDdOKCLDx0IQjTwTm03IfBa+Rm/hs747cOw5Q7O3RaTUIMPKjtVfc31Xr/XI9Abz2XEupk1/oMQ7zRA==",
"dev": true,
"requires": {
"@babel/runtime": "^7.3.1",
"css-vendor": "^2.0.8",
"jss": "10.5.0"
}
},
"locate-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
"integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
"dev": true,
"requires": {
"p-locate": "^3.0.0",
"path-exists": "^3.0.0"
}
},
"loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"dev": true,
"requires": {
"js-tokens": "^3.0.0 || ^4.0.0"
}
},
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
"requires": {
"yallist": "^4.0.0"
}
},
"make-dir": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
"integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
"dev": true,
"requires": {
"semver": "^6.0.0"
},
"dependencies": {
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"dev": true
}
}
},
"mimic-fn": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-3.1.0.tgz",
"integrity": "sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==",
"dev": true
},
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
"dev": true
},
"onetime": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
"integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
"dev": true,
"requires": {
"mimic-fn": "^2.1.0"
},
"dependencies": {
"mimic-fn": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
"dev": true
}
}
},
"p-limit": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
"dev": true,
"requires": {
"p-try": "^2.0.0"
}
},
"p-locate": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
"integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
"dev": true,
"requires": {
"p-limit": "^2.0.0"
}
},
"p-try": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
"dev": true
},
"path-exists": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
"integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
"dev": true
},
"pkg-up": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz",
"integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==",
"dev": true,
"requires": {
"find-up": "^3.0.0"
}
},
"popper.js": {
"version": "1.16.1-lts",
"resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1-lts.tgz",
"integrity": "sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA==",
"dev": true
},
"prop-types": {
"version": "15.7.2",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
"integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
"dev": true,
"requires": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
"react-is": "^16.8.1"
},
"dependencies": {
"react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
"dev": true
}
}
},
"punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
"dev": true
},
"react-is": {
"version": "17.0.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz",
"integrity": "sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==",
"dev": true
},
"react-transition-group": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz",
"integrity": "sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==",
"dev": true,
"requires": {
"@babel/runtime": "^7.5.5",
"dom-helpers": "^5.0.1",
"loose-envify": "^1.4.0",
"prop-types": "^15.6.2"
}
},
"regenerator-runtime": {
"version": "0.13.7",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz",
"integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==",
"dev": true
},
"semver": {
"version": "7.3.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
"integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
"dev": true,
"requires": {
"lru-cache": "^6.0.0"
}
},
"symbol-observable": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
"integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==",
"dev": true
},
"tiny-warning": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
"integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==",
"dev": true
},
"uri-js": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
"dev": true,
"requires": {
"punycode": "^2.1.0"
}
},
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"dev": true
}
}
}, },
"@sinonjs/commons": { "@sinonjs/commons": {
"version": "1.8.1", "version": "1.8.1",
@ -2796,7 +3433,8 @@
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
"integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=",
"dev": true "dev": true,
"optional": true
}, },
"har-schema": { "har-schema": {
"version": "2.0.0", "version": "2.0.0",
@ -3226,6 +3864,7 @@
"resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
"integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"is-docker": "^2.0.0" "is-docker": "^2.0.0"
} }
@ -4382,6 +5021,7 @@
"resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.1.tgz", "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.1.tgz",
"integrity": "sha512-BvEXF+UmsnAfYfoapKM9nGxnP+Wn7P91YfXmrKnfcYCx6VBeoN5Ez5Ogck6I8Bi5k4RlpqRYaw75pAwzX9OphA==", "integrity": "sha512-BvEXF+UmsnAfYfoapKM9nGxnP+Wn7P91YfXmrKnfcYCx6VBeoN5Ez5Ogck6I8Bi5k4RlpqRYaw75pAwzX9OphA==",
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"growly": "^1.3.0", "growly": "^1.3.0",
"is-wsl": "^2.2.0", "is-wsl": "^2.2.0",
@ -4396,6 +5036,7 @@
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"yallist": "^4.0.0" "yallist": "^4.0.0"
} }
@ -4405,6 +5046,7 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
"integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"lru-cache": "^6.0.0" "lru-cache": "^6.0.0"
} }
@ -4414,6 +5056,7 @@
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"isexe": "^2.0.0" "isexe": "^2.0.0"
} }
@ -4422,7 +5065,8 @@
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"dev": true "dev": true,
"optional": true
} }
} }
}, },
@ -5438,7 +6082,8 @@
"version": "0.1.1", "version": "0.1.1",
"resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz",
"integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==",
"dev": true "dev": true,
"optional": true
}, },
"signal-exit": { "signal-exit": {
"version": "3.0.3", "version": "3.0.3",
@ -6315,7 +6960,8 @@
"version": "8.3.1", "version": "8.3.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz",
"integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==", "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==",
"dev": true "dev": true,
"optional": true
}, },
"v8-to-istanbul": { "v8-to-istanbul": {
"version": "7.0.0", "version": "7.0.0",

View File

@ -9,13 +9,9 @@ export class PodLogsMenu extends React.Component<PodLogsMenuProps> {
Navigation.hideDetails(); Navigation.hideDetails();
const pod = this.props.object; const pod = this.props.object;
Component.createPodLogsTab({ Component.logTabStore.createPodTab({
pod, selectedPod: pod,
containers: pod.getContainers(),
initContainers: pod.getInitContainers(),
selectedContainer: container, selectedContainer: container,
showTimestamps: false,
previous: false,
}); });
} }

View File

@ -328,6 +328,7 @@
"react-refresh": "^0.9.0", "react-refresh": "^0.9.0",
"react-router-dom": "^5.2.0", "react-router-dom": "^5.2.0",
"react-select": "^3.1.0", "react-select": "^3.1.0",
"react-select-event": "^5.1.0",
"react-window": "^1.8.5", "react-window": "^1.8.5",
"sass-loader": "^8.0.2", "sass-loader": "^8.0.2",
"sharp": "^0.26.1", "sharp": "^0.26.1",

View File

@ -1,4 +1,5 @@
import { action, computed, observable } from "mobx"; import { action, computed, observable,reaction } from "mobx";
import { dockStore } from "../renderer/components/dock/dock.store";
import { autobind } from "../renderer/utils"; import { autobind } from "../renderer/utils";
export class SearchStore { export class SearchStore {
@ -6,6 +7,12 @@ export class SearchStore {
@observable occurrences: number[] = []; // Array with line numbers, eg [0, 0, 10, 21, 21, 40...] @observable occurrences: number[] = []; // Array with line numbers, eg [0, 0, 10, 21, 21, 40...]
@observable activeOverlayIndex = -1; // Index withing the occurences array. Showing where is activeOverlay currently located @observable activeOverlayIndex = -1; // Index withing the occurences array. Showing where is activeOverlay currently located
constructor() {
reaction(() => dockStore.selectedTabId, () => {
searchStore.reset();
});
}
/** /**
* Sets default activeOverlayIndex * Sets default activeOverlayIndex
* @param text An array of any textual data (logs, for example) * @param text An array of any textual data (logs, for example)

View File

@ -38,4 +38,4 @@ export * from "../../renderer/components/+events/kube-event-details";
// specific exports // specific exports
export * from "../../renderer/components/status-brick"; export * from "../../renderer/components/status-brick";
export { terminalStore, createTerminalTab } from "../../renderer/components/dock/terminal.store"; export { terminalStore, createTerminalTab } from "../../renderer/components/dock/terminal.store";
export { createPodLogsTab } from "../../renderer/components/dock/log.store"; export { logTabStore } from "../../renderer/components/dock/log-tab.store";

View File

@ -21,7 +21,7 @@ export interface KubeJsonApiData extends JsonApiData {
resourceVersion: string; resourceVersion: string;
continue?: string; continue?: string;
finalizers?: string[]; finalizers?: string[];
selfLink: string; selfLink?: string;
labels?: { labels?: {
[label: string]: string; [label: string]: string;
}; };

View File

@ -18,7 +18,7 @@ export class DaemonSetStore extends KubeObjectStore<DaemonSet> {
} }
getChildPods(daemonSet: DaemonSet): Pod[] { getChildPods(daemonSet: DaemonSet): Pod[] {
return podsStore.getPodsByOwner(daemonSet); return podsStore.getPodsByOwnerId(daemonSet.getId());
} }
getStatuses(daemonSets?: DaemonSet[]) { getStatuses(daemonSets?: DaemonSet[]) {

View File

@ -10,7 +10,7 @@ export class JobStore extends KubeObjectStore<Job> {
api = jobApi; api = jobApi;
getChildPods(job: Job): Pod[] { getChildPods(job: Job): Pod[] {
return podsStore.getPodsByOwner(job); return podsStore.getPodsByOwnerId(job.getId());
} }
getJobsByOwner(cronJob: CronJob) { getJobsByOwner(cronJob: CronJob) {

View File

@ -3,8 +3,8 @@ import { action, observable } from "mobx";
import { KubeObjectStore } from "../../kube-object.store"; import { KubeObjectStore } from "../../kube-object.store";
import { autobind, cpuUnitsToNumber, unitsToBytes } from "../../utils"; import { autobind, cpuUnitsToNumber, unitsToBytes } from "../../utils";
import { IPodMetrics, Pod, PodMetrics, podMetricsApi, podsApi } from "../../api/endpoints"; import { IPodMetrics, Pod, PodMetrics, podMetricsApi, podsApi } from "../../api/endpoints";
import { WorkloadKubeObject } from "../../api/workload-kube-object";
import { apiManager } from "../../api/api-manager"; import { apiManager } from "../../api/api-manager";
import { WorkloadKubeObject } from "../../api/workload-kube-object";
@autobind() @autobind()
export class PodsStore extends KubeObjectStore<Pod> { export class PodsStore extends KubeObjectStore<Pod> {
@ -44,6 +44,12 @@ export class PodsStore extends KubeObjectStore<Pod> {
}); });
} }
getPodsByOwnerId(workloadId: string): Pod[] {
return this.items.filter(pod => {
return pod.getOwnerRefs().find(owner => owner.uid === workloadId);
});
}
getPodsByNode(node: string) { getPodsByNode(node: string) {
if (!this.isLoaded) return []; if (!this.isLoaded) return [];

View File

@ -18,7 +18,7 @@ export class ReplicaSetStore extends KubeObjectStore<ReplicaSet> {
} }
getChildPods(replicaSet: ReplicaSet) { getChildPods(replicaSet: ReplicaSet) {
return podsStore.getPodsByOwner(replicaSet); return podsStore.getPodsByOwnerId(replicaSet.getId());
} }
getStatuses(replicaSets: ReplicaSet[]) { getStatuses(replicaSets: ReplicaSet[]) {

View File

@ -17,7 +17,7 @@ export class StatefulSetStore extends KubeObjectStore<StatefulSet> {
} }
getChildPods(statefulSet: StatefulSet) { getChildPods(statefulSet: StatefulSet) {
return podsStore.getPodsByOwner(statefulSet); return podsStore.getPodsByOwnerId(statefulSet.getId());
} }
getStatuses(statefulSets: StatefulSet[]) { getStatuses(statefulSets: StatefulSet[]) {

View File

@ -0,0 +1,103 @@
/**
* @jest-environment jsdom
*/
import React from "react";
import "@testing-library/jest-dom/extend-expect";
import { render } from "@testing-library/react";
import selectEvent from "react-select-event";
import { Pod } from "../../../api/endpoints";
import { LogResourceSelector } from "../log-resource-selector";
import { LogTabData } from "../log-tab.store";
import { dockerPod, deploymentPod1 } from "./pod.mock";
const getComponent = (tabData: LogTabData) => {
return (
<LogResourceSelector
tabId="tabId"
tabData={tabData}
save={jest.fn()}
reload={jest.fn()}
/>
);
};
const getOnePodTabData = (): LogTabData => {
const selectedPod = new Pod(dockerPod);
return {
pods: [] as Pod[],
selectedPod,
selectedContainer: selectedPod.getContainers()[0],
};
};
const getFewPodsTabData = (): LogTabData => {
const selectedPod = new Pod(deploymentPod1);
const anotherPod = new Pod(dockerPod);
return {
pods: [anotherPod],
selectedPod,
selectedContainer: selectedPod.getContainers()[0],
};
};
describe("<LogResourceSelector />", () => {
it("renders w/o errors", () => {
const tabData = getOnePodTabData();
const { container } = render(getComponent(tabData));
expect(container).toBeInstanceOf(HTMLElement);
});
it("renders proper namespace", () => {
const tabData = getOnePodTabData();
const { getByTestId } = render(getComponent(tabData));
const ns = getByTestId("namespace-badge");
expect(ns).toHaveTextContent("default");
});
it("renders proper selected items within dropdowns", () => {
const tabData = getOnePodTabData();
const { getByText } = render(getComponent(tabData));
expect(getByText("dockerExporter")).toBeInTheDocument();
expect(getByText("docker-exporter")).toBeInTheDocument();
});
it("renders sibling pods in dropdown", () => {
const tabData = getFewPodsTabData();
const { container, getByText } = render(getComponent(tabData));
const podSelector: HTMLElement = container.querySelector(".pod-selector");
selectEvent.openMenu(podSelector);
expect(getByText("dockerExporter")).toBeInTheDocument();
expect(getByText("deploymentPod1")).toBeInTheDocument();
});
it("renders sibling containers in dropdown", () => {
const tabData = getFewPodsTabData();
const { getByText, container } = render(getComponent(tabData));
const containerSelector: HTMLElement = container.querySelector(".container-selector");
selectEvent.openMenu(containerSelector);
expect(getByText("node-exporter-1")).toBeInTheDocument();
expect(getByText("init-node-exporter")).toBeInTheDocument();
expect(getByText("init-node-exporter-1")).toBeInTheDocument();
});
it("renders pod owner as dropdown title", () => {
const tabData = getFewPodsTabData();
const { getByText, container } = render(getComponent(tabData));
const podSelector: HTMLElement = container.querySelector(".pod-selector");
selectEvent.openMenu(podSelector);
expect(getByText("super-deployment")).toBeInTheDocument();
});
});

View File

@ -0,0 +1,113 @@
/**
* @jest-environment jsdom
*/
import { podsStore } from "../../+workloads-pods/pods.store";
import { Pod } from "../../../api/endpoints";
import { dockStore } from "../dock.store";
import { logTabStore } from "../log-tab.store";
import { deploymentPod1, deploymentPod2, deploymentPod3, dockerPod } from "./pod.mock";
podsStore.items.push(new Pod(dockerPod));
podsStore.items.push(new Pod(deploymentPod1));
podsStore.items.push(new Pod(deploymentPod2));
describe("log tab store", () => {
afterEach(() => {
logTabStore.reset();
dockStore.reset();
});
it("creates log tab without sibling pods", () => {
const selectedPod = new Pod(dockerPod);
const selectedContainer = selectedPod.getAllContainers()[0];
logTabStore.createPodTab({
selectedPod,
selectedContainer
});
expect(logTabStore.getData(dockStore.selectedTabId)).toEqual({
pods: [selectedPod],
selectedPod,
selectedContainer,
showTimestamps: false,
previous: false
});
});
it("creates log tab with sibling pods", () => {
const selectedPod = new Pod(deploymentPod1);
const siblingPod = new Pod(deploymentPod2);
const selectedContainer = selectedPod.getInitContainers()[0];
logTabStore.createPodTab({
selectedPod,
selectedContainer
});
expect(logTabStore.getData(dockStore.selectedTabId)).toEqual({
pods: [selectedPod, siblingPod],
selectedPod,
selectedContainer,
showTimestamps: false,
previous: false
});
});
it("removes item from pods list if pod deleted from store", () => {
const selectedPod = new Pod(deploymentPod1);
const selectedContainer = selectedPod.getInitContainers()[0];
logTabStore.createPodTab({
selectedPod,
selectedContainer
});
podsStore.items.pop();
expect(logTabStore.getData(dockStore.selectedTabId)).toEqual({
pods: [selectedPod],
selectedPod,
selectedContainer,
showTimestamps: false,
previous: false
});
});
it("adds item into pods list if new sibling pod added to store", () => {
const selectedPod = new Pod(deploymentPod1);
const selectedContainer = selectedPod.getInitContainers()[0];
logTabStore.createPodTab({
selectedPod,
selectedContainer
});
podsStore.items.push(new Pod(deploymentPod3));
expect(logTabStore.getData(dockStore.selectedTabId)).toEqual({
pods: [selectedPod, deploymentPod3],
selectedPod,
selectedContainer,
showTimestamps: false,
previous: false
});
});
it("closes tab if no pods left in store", () => {
const selectedPod = new Pod(deploymentPod1);
const selectedContainer = selectedPod.getInitContainers()[0];
logTabStore.createPodTab({
selectedPod,
selectedContainer
});
podsStore.items.clear();
expect(logTabStore.getData(dockStore.selectedTabId)).toBeUndefined();
expect(dockStore.getTabById(dockStore.selectedTabId)).toBeUndefined();
});
});

View File

@ -0,0 +1,203 @@
export const dockerPod = {
apiVersion: "v1",
kind: "dummy",
metadata: {
uid: "dockerExporter",
name: "dockerExporter",
creationTimestamp: "dummy",
resourceVersion: "dummy",
namespace: "default"
},
spec: {
initContainers: [] as any,
containers: [
{
name: "docker-exporter",
image: "docker.io/prom/node-exporter:v1.0.0-rc.0",
imagePullPolicy: "pull"
}
],
serviceAccountName: "dummy",
serviceAccount: "dummy",
},
status: {
phase: "Running",
conditions: [{
type: "Running",
status: "Running",
lastProbeTime: 1,
lastTransitionTime: "Some time",
}],
hostIP: "dummy",
podIP: "dummy",
startTime: "dummy",
}
};
export const deploymentPod1 = {
apiVersion: "v1",
kind: "dummy",
metadata: {
uid: "deploymentPod1",
name: "deploymentPod1",
creationTimestamp: "dummy",
resourceVersion: "dummy",
namespace: "default",
ownerReferences: [{
apiVersion: "v1",
kind: "Deployment",
name: "super-deployment",
uid: "uuid",
controller: true,
blockOwnerDeletion: true,
}]
},
spec: {
initContainers: [
{
name: "init-node-exporter",
image: "docker.io/prom/node-exporter:v1.0.0-rc.0",
imagePullPolicy: "pull"
},
{
name: "init-node-exporter-1",
image: "docker.io/prom/node-exporter:v1.0.0-rc.0",
imagePullPolicy: "pull"
}
],
containers: [
{
name: "node-exporter",
image: "docker.io/prom/node-exporter:v1.0.0-rc.0",
imagePullPolicy: "pull"
},
{
name: "node-exporter-1",
image: "docker.io/prom/node-exporter:v1.0.0-rc.0",
imagePullPolicy: "pull"
}
],
serviceAccountName: "dummy",
serviceAccount: "dummy",
},
status: {
phase: "Running",
conditions: [{
type: "Running",
status: "Running",
lastProbeTime: 1,
lastTransitionTime: "Some time",
}],
hostIP: "dummy",
podIP: "dummy",
startTime: "dummy",
}
};
export const deploymentPod2 = {
apiVersion: "v1",
kind: "dummy",
metadata: {
uid: "deploymentPod2",
name: "deploymentPod2",
creationTimestamp: "dummy",
resourceVersion: "dummy",
namespace: "default",
ownerReferences: [{
apiVersion: "v1",
kind: "Deployment",
name: "super-deployment",
uid: "uuid",
controller: true,
blockOwnerDeletion: true,
}]
},
spec: {
initContainers: [
{
name: "init-node-exporter",
image: "docker.io/prom/node-exporter:v1.0.0-rc.0",
imagePullPolicy: "pull"
},
{
name: "init-node-exporter-1",
image: "docker.io/prom/node-exporter:v1.0.0-rc.0",
imagePullPolicy: "pull"
}
],
containers: [
{
name: "node-exporter",
image: "docker.io/prom/node-exporter:v1.0.0-rc.0",
imagePullPolicy: "pull"
},
{
name: "node-exporter-1",
image: "docker.io/prom/node-exporter:v1.0.0-rc.0",
imagePullPolicy: "pull"
}
],
serviceAccountName: "dummy",
serviceAccount: "dummy",
},
status: {
phase: "Running",
conditions: [{
type: "Running",
status: "Running",
lastProbeTime: 1,
lastTransitionTime: "Some time",
}],
hostIP: "dummy",
podIP: "dummy",
startTime: "dummy",
}
};
export const deploymentPod3 = {
apiVersion: "v1",
kind: "dummy",
metadata: {
uid: "deploymentPod3",
name: "deploymentPod3",
creationTimestamp: "dummy",
resourceVersion: "dummy",
namespace: "default",
ownerReferences: [{
apiVersion: "v1",
kind: "Deployment",
name: "super-deployment",
uid: "uuid",
controller: true,
blockOwnerDeletion: true,
}]
},
spec: {
containers: [
{
name: "node-exporter",
image: "docker.io/prom/node-exporter:v1.0.0-rc.0",
imagePullPolicy: "pull"
},
{
name: "node-exporter-1",
image: "docker.io/prom/node-exporter:v1.0.0-rc.0",
imagePullPolicy: "pull"
}
],
serviceAccountName: "dummy",
serviceAccount: "dummy",
},
status: {
phase: "Running",
conditions: [{
type: "Running",
status: "Running",
lastProbeTime: 1,
lastTransitionTime: "Some time",
}],
hostIP: "dummy",
podIP: "dummy",
startTime: "dummy",
}
};

View File

@ -7,7 +7,7 @@ import { DockTab } from "./dock-tab";
import { IDockTab } from "./dock.store"; import { IDockTab } from "./dock.store";
import { isEditResourceTab } from "./edit-resource.store"; import { isEditResourceTab } from "./edit-resource.store";
import { isInstallChartTab } from "./install-chart.store"; import { isInstallChartTab } from "./install-chart.store";
import { isLogsTab } from "./log.store"; import { isLogsTab } from "./log-tab.store";
import { TerminalTab } from "./terminal-tab"; import { TerminalTab } from "./terminal-tab";
import { isTerminalTab } from "./terminal.store"; import { isTerminalTab } from "./terminal.store";
import { isUpgradeChartTab } from "./upgrade-chart.store"; import { isUpgradeChartTab } from "./upgrade-chart.store";

View File

@ -208,6 +208,12 @@ export class DockStore {
this.closeTabs(tabs); this.closeTabs(tabs);
} }
renameTab(tabId: TabId, title: string) {
const tab = this.getTabById(tabId);
tab.title = title;
}
@action @action
selectTab(tabId: TabId) { selectTab(tabId: TabId) {
this.selectedTabId = this.getTabById(tabId)?.id ?? null; this.selectedTabId = this.getTabById(tabId)?.id ?? null;

View File

@ -17,7 +17,7 @@ import { isEditResourceTab } from "./edit-resource.store";
import { InstallChart } from "./install-chart"; import { InstallChart } from "./install-chart";
import { isInstallChartTab } from "./install-chart.store"; import { isInstallChartTab } from "./install-chart.store";
import { Logs } from "./logs"; import { Logs } from "./logs";
import { isLogsTab } from "./log.store"; import { isLogsTab } from "./log-tab.store";
import { TerminalWindow } from "./terminal-window"; import { TerminalWindow } from "./terminal-window";
import { createTerminalTab, isTerminalTab } from "./terminal.store"; import { createTerminalTab, isTerminalTab } from "./terminal.store";
import { UpgradeChart } from "./upgrade-chart"; import { UpgradeChart } from "./upgrade-chart";

View File

@ -5,22 +5,23 @@ import { observer } from "mobx-react";
import { Pod } from "../../api/endpoints"; import { Pod } from "../../api/endpoints";
import { cssNames, saveFileDialog } from "../../utils"; import { cssNames, saveFileDialog } from "../../utils";
import { IPodLogsData, podLogsStore } from "./log.store"; import { logStore } from "./log.store";
import { Checkbox } from "../checkbox"; import { Checkbox } from "../checkbox";
import { Icon } from "../icon"; import { Icon } from "../icon";
import { LogTabData } from "./log-tab.store";
interface Props { interface Props {
tabData: IPodLogsData tabData: LogTabData
logs: string[] logs: string[]
save: (data: Partial<IPodLogsData>) => void save: (data: Partial<LogTabData>) => void
reload: () => void reload: () => void
} }
export const LogControls = observer((props: Props) => { export const LogControls = observer((props: Props) => {
const { tabData, save, reload, logs } = props; const { tabData, save, reload, logs } = props;
const { showTimestamps, previous } = tabData; const { showTimestamps, previous } = tabData;
const since = logs.length ? podLogsStore.getTimestamps(logs[0]) : null; const since = logs.length ? logStore.getTimestamps(logs[0]) : null;
const pod = new Pod(tabData.pod); const pod = new Pod(tabData.selectedPod);
const toggleTimestamps = () => { const toggleTimestamps = () => {
save({ showTimestamps: !showTimestamps }); save({ showTimestamps: !showTimestamps });
@ -33,7 +34,7 @@ export const LogControls = observer((props: Props) => {
const downloadLogs = () => { const downloadLogs = () => {
const fileName = pod.getName(); const fileName = pod.getName();
const logsToDownload = showTimestamps ? logs : podLogsStore.logsWithoutTimestamps; const logsToDownload = showTimestamps ? logs : logStore.logsWithoutTimestamps;
saveFileDialog(`${fileName}.log`, logsToDownload.join("\n"), "text/plain"); saveFileDialog(`${fileName}.log`, logsToDownload.join("\n"), "text/plain");
}; };

View File

@ -14,7 +14,8 @@ import { Button } from "../button";
import { Icon } from "../icon"; import { Icon } from "../icon";
import { Spinner } from "../spinner"; import { Spinner } from "../spinner";
import { VirtualList } from "../virtual-list"; import { VirtualList } from "../virtual-list";
import { podLogsStore } from "./log.store"; import { logStore } from "./log.store";
import { logTabStore } from "./log-tab.store";
interface Props { interface Props {
logs: string[] logs: string[]
@ -77,10 +78,10 @@ export class LogList extends React.Component<Props> {
*/ */
@computed @computed
get logs() { get logs() {
const showTimestamps = podLogsStore.getData(this.props.id).showTimestamps; const showTimestamps = logTabStore.getData(this.props.id).showTimestamps;
if (!showTimestamps) { if (!showTimestamps) {
return podLogsStore.logsWithoutTimestamps; return logStore.logsWithoutTimestamps;
} }
return this.props.logs; return this.props.logs;

View File

@ -1,27 +1,30 @@
import "./log-resource-selector.scss"; import "./log-resource-selector.scss";
import React from "react"; import React, { useEffect } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { IPodContainer, Pod } from "../../api/endpoints"; import { Pod } from "../../api/endpoints";
import { Badge } from "../badge"; import { Badge } from "../badge";
import { Select, SelectOption } from "../select"; import { Select, SelectOption } from "../select";
import { IPodLogsData } from "./log.store"; import { LogTabData, logTabStore } from "./log-tab.store";
import { podsStore } from "../+workloads-pods/pods.store";
import { TabId } from "./dock.store";
interface Props { interface Props {
tabData: IPodLogsData tabId: TabId
save: (data: Partial<IPodLogsData>) => void tabData: LogTabData
save: (data: Partial<LogTabData>) => void
reload: () => void reload: () => void
} }
export const LogResourceSelector = observer((props: Props) => { export const LogResourceSelector = observer((props: Props) => {
const { tabData, save, reload } = props; const { tabData, save, reload, tabId } = props;
const { selectedContainer, containers, initContainers } = tabData; const { selectedPod, selectedContainer, pods } = tabData;
const pod = new Pod(tabData.pod); const pod = new Pod(selectedPod);
const containers = pod.getContainers();
const initContainers = pod.getInitContainers();
const onContainerChange = (option: SelectOption) => { const onContainerChange = (option: SelectOption) => {
const { containers, initContainers } = tabData;
save({ save({
selectedContainer: containers selectedContainer: containers
.concat(initContainers) .concat(initContainers)
@ -30,11 +33,18 @@ export const LogResourceSelector = observer((props: Props) => {
reload(); reload();
}; };
const getSelectOptions = (containers: IPodContainer[]) => { const onPodChange = (option: SelectOption) => {
return containers.map(container => { const selectedPod = podsStore.getByName(option.value, pod.getNs());
save({ selectedPod });
logTabStore.renameTab(tabId);
};
const getSelectOptions = (items: string[]) => {
return items.map(item => {
return { return {
value: container.name, value: item,
label: container.name label: item
}; };
}); });
}; };
@ -42,24 +52,43 @@ export const LogResourceSelector = observer((props: Props) => {
const containerSelectOptions = [ const containerSelectOptions = [
{ {
label: `Containers`, label: `Containers`,
options: getSelectOptions(containers) options: getSelectOptions(containers.map(container => container.name))
}, },
{ {
label: `Init Containers`, label: `Init Containers`,
options: getSelectOptions(initContainers), options: getSelectOptions(initContainers.map(container => container.name)),
} }
]; ];
const podSelectOptions = [
{
label: pod.getOwnerRefs()[0]?.name,
options: getSelectOptions(pods.map(pod => pod.metadata.name))
}
];
useEffect(() => {
reload();
}, [selectedPod]);
return ( return (
<div className="LogResourceSelector flex gaps align-center"> <div className="LogResourceSelector flex gaps align-center">
<span>Namespace</span> <Badge label={pod.getNs()}/> <span>Namespace</span> <Badge data-testid="namespace-badge" label={pod.getNs()}/>
<span>Pod</span> <Badge label={pod.getName()}/> <span>Pod</span>
<Select
options={podSelectOptions}
value={{ label: pod.getName(), value: pod.getName() }}
onChange={onPodChange}
autoConvertOptions={false}
className="pod-selector"
/>
<span>Container</span> <span>Container</span>
<Select <Select
options={containerSelectOptions} options={containerSelectOptions}
value={{ label: selectedContainer.name, value: selectedContainer.name }} value={{ label: selectedContainer.name, value: selectedContainer.name }}
onChange={onContainerChange} onChange={onContainerChange}
autoConvertOptions={false} autoConvertOptions={false}
className="container-selector"
/> />
</div> </div>
); );

View File

@ -0,0 +1,123 @@
import uniqueId from "lodash/uniqueId";
import { reaction } from "mobx";
import { podsStore } from "../+workloads-pods/pods.store";
import { IPodContainer, Pod } from "../../api/endpoints";
import { WorkloadKubeObject } from "../../api/workload-kube-object";
import { DockTabStore } from "./dock-tab.store";
import { dockStore, IDockTab, TabKind } from "./dock.store";
export interface LogTabData {
pods: Pod[];
selectedPod: Pod;
selectedContainer: IPodContainer
showTimestamps?: boolean
previous?: boolean
}
interface PodLogsTabData {
selectedPod: Pod
selectedContainer: IPodContainer
}
interface WorkloadLogsTabData {
workload: WorkloadKubeObject
}
export class LogTabStore extends DockTabStore<LogTabData> {
constructor() {
super({
storageName: "pod_logs"
});
reaction(() => podsStore.items.length, () => {
this.updateTabsData();
});
}
createPodTab({ selectedPod, selectedContainer }: PodLogsTabData): void {
const podOwner = selectedPod.getOwnerRefs()[0];
const pods = podsStore.getPodsByOwnerId(podOwner?.uid);
const title = `Pod ${selectedPod.getName()}`;
this.createLogsTab(title, {
pods: pods.length ? pods : [selectedPod],
selectedPod,
selectedContainer
});
}
createWorkloadTab({ workload }: WorkloadLogsTabData): void {
const pods = podsStore.getPodsByOwnerId(workload.getId());
if (!pods.length) return;
const selectedPod = pods[0];
const selectedContainer = selectedPod.getAllContainers()[0];
const title = `${workload.kind} ${selectedPod.getName()}`;
this.createLogsTab(title, {
pods,
selectedPod,
selectedContainer
});
}
renameTab(tabId: string) {
const { selectedPod } = this.getData(tabId);
dockStore.renameTab(tabId, `Pod ${selectedPod.metadata.name}`);
}
private createDockTab(tabParams: Partial<IDockTab>) {
dockStore.createTab({
kind: TabKind.POD_LOGS,
...tabParams
}, false);
}
private createLogsTab(title: string, data: LogTabData) {
const id = uniqueId("log-tab-");
this.createDockTab({ id, title });
this.setData(id, {
...data,
showTimestamps: false,
previous: false
});
}
private updateTabsData() {
this.data.forEach((tabData, tabId) => {
const pod = new Pod(tabData.selectedPod);
const pods = podsStore.getPodsByOwnerId(pod.getOwnerRefs()[0]?.uid);
const isSelectedPodInList = pods.find(item => item.getId() == pod.getId());
const selectedPod = isSelectedPodInList ? pod : pods[0];
const selectedContainer = isSelectedPodInList ? tabData.selectedContainer : pod.getAllContainers()[0];
if (pods.length) {
this.setData(tabId, {
...tabData,
selectedPod,
selectedContainer,
pods
});
this.renameTab(tabId);
} else {
this.closeTab(tabId);
}
});
}
private closeTab(tabId: string) {
this.clearData(tabId);
dockStore.closeTab(tabId);
}
}
export const logTabStore = new LogTabStore();
export function isLogsTab(tab: IDockTab) {
return tab && tab.kind === TabKind.POD_LOGS;
}

View File

@ -1,27 +1,16 @@
import { autorun, computed, observable, reaction } from "mobx"; import { autorun, computed, observable } from "mobx";
import { Pod, IPodContainer, podsApi, IPodLogsQuery } from "../../api/endpoints";
import { IPodLogsQuery, Pod, podsApi } from "../../api/endpoints";
import { autobind, interval } from "../../utils"; import { autobind, interval } from "../../utils";
import { DockTabStore } from "./dock-tab.store"; import { dockStore, TabId } from "./dock.store";
import { dockStore, IDockTab, TabKind } from "./dock.store"; import { isLogsTab, logTabStore } from "./log-tab.store";
import { searchStore } from "../../../common/search-store";
export interface IPodLogsData {
pod: Pod;
selectedContainer: IPodContainer
containers: IPodContainer[]
initContainers: IPodContainer[]
showTimestamps: boolean
previous: boolean
}
type TabId = string;
type PodLogLine = string; type PodLogLine = string;
// Number for log lines to load const logLinesToLoad = 500;
export const logRange = 500;
@autobind() @autobind()
export class LogStore extends DockTabStore<IPodLogsData> { export class LogStore {
private refresher = interval(10, () => { private refresher = interval(10, () => {
const id = dockStore.selectedTabId; const id = dockStore.selectedTabId;
@ -30,12 +19,8 @@ export class LogStore extends DockTabStore<IPodLogsData> {
}); });
@observable podLogs = observable.map<TabId, PodLogLine[]>(); @observable podLogs = observable.map<TabId, PodLogLine[]>();
@observable newLogSince = observable.map<TabId, string>(); // Timestamp after which all logs are considered to be new
constructor() { constructor() {
super({
storageName: "pod_logs"
});
autorun(() => { autorun(() => {
const { selectedTab, isOpen } = dockStore; const { selectedTab, isOpen } = dockStore;
@ -45,15 +30,6 @@ export class LogStore extends DockTabStore<IPodLogsData> {
this.refresher.stop(); this.refresher.stop();
} }
}, { delay: 500 }); }, { delay: 500 });
reaction(() => this.podLogs.get(dockStore.selectedTabId), () => {
this.setNewLogSince(dockStore.selectedTabId);
});
reaction(() => dockStore.selectedTabId, () => {
// Clear search query on tab change
searchStore.reset();
});
} }
/** /**
@ -66,7 +42,7 @@ export class LogStore extends DockTabStore<IPodLogsData> {
load = async (tabId: TabId) => { load = async (tabId: TabId) => {
try { try {
const logs = await this.loadLogs(tabId, { const logs = await this.loadLogs(tabId, {
tailLines: this.lines + logRange tailLines: this.lines + logLinesToLoad
}); });
this.refresher.start(); this.refresher.start();
@ -107,9 +83,9 @@ export class LogStore extends DockTabStore<IPodLogsData> {
* @returns {Promise} A fetch request promise * @returns {Promise} A fetch request promise
*/ */
loadLogs = async (tabId: TabId, params: Partial<IPodLogsQuery>) => { loadLogs = async (tabId: TabId, params: Partial<IPodLogsQuery>) => {
const data = this.getData(tabId); const data = logTabStore.getData(tabId);
const { selectedContainer, previous } = data; const { selectedContainer, previous } = data;
const pod = new Pod(data.pod); const pod = new Pod(data.selectedPod);
const namespace = pod.getNs(); const namespace = pod.getNs();
const name = pod.getName(); const name = pod.getName();
@ -127,17 +103,6 @@ export class LogStore extends DockTabStore<IPodLogsData> {
}); });
}; };
/**
* Sets newLogSince separator timestamp to split old logs from new ones
* @param tabId
*/
setNewLogSince(tabId: TabId) {
if (!this.podLogs.has(tabId) || !this.podLogs.get(tabId).length || this.newLogSince.has(tabId)) return;
const timestamp = this.getLastSinceTime(tabId);
this.newLogSince.set(tabId, timestamp.split(".")[0]); // Removing milliseconds from string
}
/** /**
* Converts logs into a string array * Converts logs into a string array
* @returns {number} Length of log lines * @returns {number} Length of log lines
@ -196,37 +161,6 @@ export class LogStore extends DockTabStore<IPodLogsData> {
clearLogs(tabId: TabId) { clearLogs(tabId: TabId) {
this.podLogs.delete(tabId); this.podLogs.delete(tabId);
} }
clearData(tabId: TabId) {
this.data.delete(tabId);
this.clearLogs(tabId);
}
} }
export const podLogsStore = new LogStore(); export const logStore = new LogStore();
export function createPodLogsTab(data: IPodLogsData, tabParams: Partial<IDockTab> = {}) {
const podId = data.pod.getId();
let tab = dockStore.getTabById(podId);
if (tab) {
dockStore.open();
dockStore.selectTab(tab.id);
return;
}
// If no existent tab found
tab = dockStore.createTab({
id: podId,
kind: TabKind.POD_LOGS,
title: data.pod.getName(),
...tabParams
}, false);
podLogsStore.setData(tab.id, data);
return tab;
}
export function isLogsTab(tab: IDockTab) {
return tab && tab.kind === TabKind.POD_LOGS;
}

View File

@ -8,9 +8,10 @@ import { IDockTab } from "./dock.store";
import { InfoPanel } from "./info-panel"; import { InfoPanel } from "./info-panel";
import { LogResourceSelector } from "./log-resource-selector"; import { LogResourceSelector } from "./log-resource-selector";
import { LogList } from "./log-list"; import { LogList } from "./log-list";
import { IPodLogsData, podLogsStore } from "./log.store"; import { logStore } from "./log.store";
import { LogSearch } from "./log-search"; import { LogSearch } from "./log-search";
import { LogControls } from "./log-controls"; import { LogControls } from "./log-controls";
import { LogTabData, logTabStore } from "./log-tab.store";
interface Props { interface Props {
className?: string className?: string
@ -30,7 +31,7 @@ export class Logs extends React.Component<Props> {
} }
get tabData() { get tabData() {
return podLogsStore.getData(this.tabId); return logTabStore.getData(this.tabId);
} }
get tabId() { get tabId() {
@ -38,18 +39,18 @@ export class Logs extends React.Component<Props> {
} }
@autobind() @autobind()
save(data: Partial<IPodLogsData>) { save(data: Partial<LogTabData>) {
podLogsStore.setData(this.tabId, { ...this.tabData, ...data }); logTabStore.setData(this.tabId, { ...this.tabData, ...data });
} }
load = async () => { load = async () => {
this.isLoading = true; this.isLoading = true;
await podLogsStore.load(this.tabId); await logStore.load(this.tabId);
this.isLoading = false; this.isLoading = false;
}; };
reload = async () => { reload = async () => {
podLogsStore.clearLogs(this.tabId); logStore.clearLogs(this.tabId);
await this.load(); await this.load();
}; };
@ -82,11 +83,12 @@ export class Logs extends React.Component<Props> {
} }
renderResourceSelector() { renderResourceSelector() {
const logs = podLogsStore.logs; const logs = logStore.logs;
const searchLogs = this.tabData.showTimestamps ? logs : podLogsStore.logsWithoutTimestamps; const searchLogs = this.tabData.showTimestamps ? logs : logStore.logsWithoutTimestamps;
const controls = ( const controls = (
<div className="flex gaps"> <div className="flex gaps">
<LogResourceSelector <LogResourceSelector
tabId={this.tabId}
tabData={this.tabData} tabData={this.tabData}
save={this.save} save={this.save}
reload={this.reload} reload={this.reload}
@ -112,7 +114,7 @@ export class Logs extends React.Component<Props> {
} }
render() { render() {
const logs = podLogsStore.logs; const logs = logStore.logs;
return ( return (
<div className="PodLogs flex column"> <div className="PodLogs flex column">

View File

@ -47,6 +47,10 @@ export abstract class KubeObjectStore<T extends KubeObject = any> extends ItemSt
} }
} }
getById(id: string) {
return this.items.find(item => item.getId() === id);
}
getByName(name: string, namespace?: string): T { getByName(name: string, namespace?: string): T {
return this.items.find(item => { return this.items.find(item => {
return item.getName() === name && ( return item.getName() === name && (

View File

@ -267,6 +267,13 @@
dependencies: dependencies:
regenerator-runtime "^0.13.4" regenerator-runtime "^0.13.4"
"@babel/runtime@^7.12.5":
version "7.12.5"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e"
integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==
dependencies:
regenerator-runtime "^0.13.4"
"@babel/template@^7.10.1", "@babel/template@^7.3.3": "@babel/template@^7.10.1", "@babel/template@^7.3.3":
version "7.10.1" version "7.10.1"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.1.tgz#e167154a94cb5f14b28dc58f5356d2162f539811" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.1.tgz#e167154a94cb5f14b28dc58f5356d2162f539811"
@ -775,6 +782,17 @@
"@types/yargs" "^15.0.0" "@types/yargs" "^15.0.0"
chalk "^4.0.0" chalk "^4.0.0"
"@jest/types@^26.6.2":
version "26.6.2"
resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e"
integrity sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==
dependencies:
"@types/istanbul-lib-coverage" "^2.0.0"
"@types/istanbul-reports" "^3.0.0"
"@types/node" "*"
"@types/yargs" "^15.0.0"
chalk "^4.0.0"
"@kubernetes/client-node@^0.12.0": "@kubernetes/client-node@^0.12.0":
version "0.12.0" version "0.12.0"
resolved "https://registry.yarnpkg.com/@kubernetes/client-node/-/client-node-0.12.0.tgz#79120311bced206ac8fa36435fb4cc2c1828fff2" resolved "https://registry.yarnpkg.com/@kubernetes/client-node/-/client-node-0.12.0.tgz#79120311bced206ac8fa36435fb4cc2c1828fff2"
@ -955,6 +973,20 @@
dependencies: dependencies:
defer-to-connect "^1.0.1" defer-to-connect "^1.0.1"
"@testing-library/dom@>=7":
version "7.29.4"
resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-7.29.4.tgz#1647c2b478789621ead7a50614ad81ab5ae5b86c"
integrity sha512-CtrJRiSYEfbtNGtEsd78mk1n1v2TUbeABlNIcOCJdDfkN5/JTOwQEbbQpoSRxGqzcWPgStMvJ4mNolSuBRv1NA==
dependencies:
"@babel/code-frame" "^7.10.4"
"@babel/runtime" "^7.12.5"
"@types/aria-query" "^4.2.0"
aria-query "^4.2.2"
chalk "^4.1.0"
dom-accessibility-api "^0.5.4"
lz-string "^1.4.4"
pretty-format "^26.6.2"
"@testing-library/dom@^7.26.0": "@testing-library/dom@^7.26.0":
version "7.26.3" version "7.26.3"
resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-7.26.3.tgz#5554ee985f712d621bd676104b879f85d9a7a0ef" resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-7.26.3.tgz#5554ee985f712d621bd676104b879f85d9a7a0ef"
@ -4552,7 +4584,7 @@ doctrine@^3.0.0:
dependencies: dependencies:
esutils "^2.0.2" esutils "^2.0.2"
dom-accessibility-api@^0.5.1: dom-accessibility-api@^0.5.1, dom-accessibility-api@^0.5.4:
version "0.5.4" version "0.5.4"
resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.4.tgz#b06d059cdd4a4ad9a79275f9d414a5c126241166" resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.4.tgz#b06d059cdd4a4ad9a79275f9d414a5c126241166"
integrity sha512-TvrjBckDy2c6v6RLxPv5QXOnU+SmF9nBII5621Ve5fu6Z/BDrENurBEvlC1f44lKEUVqOpK4w9E5Idc5/EgkLQ== integrity sha512-TvrjBckDy2c6v6RLxPv5QXOnU+SmF9nBII5621Ve5fu6Z/BDrENurBEvlC1f44lKEUVqOpK4w9E5Idc5/EgkLQ==
@ -10822,6 +10854,16 @@ pretty-format@^26.0.1:
ansi-styles "^4.0.0" ansi-styles "^4.0.0"
react-is "^16.12.0" react-is "^16.12.0"
pretty-format@^26.6.2:
version "26.6.2"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93"
integrity sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==
dependencies:
"@jest/types" "^26.6.2"
ansi-regex "^5.0.0"
ansi-styles "^4.0.0"
react-is "^17.0.1"
process-nextick-args@~2.0.0: process-nextick-args@~2.0.0:
version "2.0.1" version "2.0.1"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
@ -11198,6 +11240,13 @@ react-router@5.2.0, react-router@^5.2.0:
tiny-invariant "^1.0.2" tiny-invariant "^1.0.2"
tiny-warning "^1.0.0" tiny-warning "^1.0.0"
react-select-event@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/react-select-event/-/react-select-event-5.1.0.tgz#d45ef68f2a9c872903e8c9725f3ae6e7576f7be0"
integrity sha512-D5DzJlYCdZsGbDVFMQFynrG0OLalJM3ZzDT7KQADNVWE604JCeQF9bIuvPZqVD7IzhnPsFzOUCsilzDA6w6WRQ==
dependencies:
"@testing-library/dom" ">=7"
react-select@^3.1.0: react-select@^3.1.0:
version "3.1.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/react-select/-/react-select-3.1.0.tgz#ab098720b2e9fe275047c993f0d0caf5ded17c27" resolved "https://registry.yarnpkg.com/react-select/-/react-select-3.1.0.tgz#ab098720b2e9fe275047c993f0d0caf5ded17c27"