From 643e01d67c2ca97f5817a7ad8444903e667e36bb Mon Sep 17 00:00:00 2001 From: Ousmane Samba Date: Tue, 14 Nov 2023 16:01:14 +0100 Subject: [PATCH 1/5] use store to get extractors list --- .../components/extractors/ExtractorsList.jsx | 13 ++++++----- .../src/stores/extractors/ExtractorsStore.js | 23 ++++++++++++++++--- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/graylog2-web-interface/src/components/extractors/ExtractorsList.jsx b/graylog2-web-interface/src/components/extractors/ExtractorsList.jsx index 342cb923473a..81d3fab461a1 100644 --- a/graylog2-web-interface/src/components/extractors/ExtractorsList.jsx +++ b/graylog2-web-interface/src/components/extractors/ExtractorsList.jsx @@ -22,21 +22,22 @@ import { Row, Col, Button } from 'components/bootstrap'; import Spinner from 'components/common/Spinner'; import AddExtractorWizard from 'components/extractors/AddExtractorWizard'; import EntityList from 'components/common/EntityList'; -import { ExtractorsActions } from 'stores/extractors/ExtractorsStore'; +import { ExtractorsActions, ExtractorsStore } from 'stores/extractors/ExtractorsStore'; +import { useStore } from 'stores/connect'; import ExtractorsListItem from './ExtractorsListItem'; import ExtractorsSortModal from './ExtractorSortModal'; -const fetchExtractors = (inputId, callback) => { - ExtractorsActions.list.triggerPromise(inputId).then((data) => callback(data?.extractors)); +const fetchExtractors = (inputId) => { + ExtractorsActions.list.triggerPromise(inputId); }; const ExtractorsList = ({ input, node }) => { - const [extractors, setExtractors] = useState(null); const [showSortModal, setShowSortModal] = useState(false); + const extractors = useStore(ExtractorsStore, (state) => state.extractors); useEffect(() => { - fetchExtractors(input.id, setExtractors); + fetchExtractors(input.id); }, [input.id]); const _formatExtractor = (extractor) => ( @@ -92,7 +93,7 @@ const ExtractorsList = ({ input, node }) => { setShowSortModal(false)} - onSort={() => fetchExtractors(input.id, setExtractors)} /> + onSort={() => fetchExtractors(input.id)} /> )} ); diff --git a/graylog2-web-interface/src/stores/extractors/ExtractorsStore.js b/graylog2-web-interface/src/stores/extractors/ExtractorsStore.js index 79ea30d0bddf..58c7e81e3c73 100644 --- a/graylog2-web-interface/src/stores/extractors/ExtractorsStore.js +++ b/graylog2-web-interface/src/stores/extractors/ExtractorsStore.js @@ -62,8 +62,23 @@ export const ExtractorsStore = singletonStore( extractors: undefined, extractor: undefined, + getInitialState() { + return this.getState(); + }, + init() { - this.trigger({ extractors: this.extractors, extractor: this.extractor }); + this.trigger({ extractors: this.extractors, extractor: this.extractory }); + }, + + getState() { + return { + extractors: this.extractors, + extractor: this.extractor, + }; + }, + + propagateState() { + this.trigger(this.getState()); }, list(inputId) { @@ -71,7 +86,7 @@ export const ExtractorsStore = singletonStore( promise.then((response) => { this.extractors = response.extractors; - this.trigger({ extractors: this.extractors }); + this.propagateState(); }); ExtractorsActions.list.promise(promise); @@ -97,7 +112,7 @@ export const ExtractorsStore = singletonStore( promise.then((response) => { this.extractor = response; - this.trigger({ extractor: this.extractor }); + this.propagateState(); }); ExtractorsActions.get.promise(promise); @@ -235,6 +250,8 @@ export const ExtractorsStore = singletonStore( if (failedImports === 0) { UserNotification.success(`Import results: ${successfulImports} extractor(s) imported.`, 'Import operation successful'); + + this.propagateState(); } else { UserNotification.warning(`Import results: ${successfulImports} extractor(s) imported, ${failedImports} error(s).`, 'Import operation completed'); From b80d39671ed5632aea0cf4e6cddebffdf52e917a Mon Sep 17 00:00:00 2001 From: Ousmane Samba Date: Tue, 14 Nov 2023 16:16:14 +0100 Subject: [PATCH 2/5] add changelog --- changelog/unreleased/pr-17289.toml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changelog/unreleased/pr-17289.toml diff --git a/changelog/unreleased/pr-17289.toml b/changelog/unreleased/pr-17289.toml new file mode 100644 index 000000000000..4fd07117bba5 --- /dev/null +++ b/changelog/unreleased/pr-17289.toml @@ -0,0 +1,5 @@ +type = "fixed" +message = "Fix inputs extractors list not updating after deletion" + +issues = ["16858"] +pulls = ["17289"] From 039b548afde463a3ff150f464244d2732668b15c Mon Sep 17 00:00:00 2001 From: Ousmane Samba Date: Wed, 15 Nov 2023 15:07:23 +0100 Subject: [PATCH 3/5] remove getInitialState to use default from store --- graylog2-web-interface/src/pages/EditExtractorsPage.jsx | 7 ------- 1 file changed, 7 deletions(-) diff --git a/graylog2-web-interface/src/pages/EditExtractorsPage.jsx b/graylog2-web-interface/src/pages/EditExtractorsPage.jsx index 99062ebc0091..a431c990a4d1 100644 --- a/graylog2-web-interface/src/pages/EditExtractorsPage.jsx +++ b/graylog2-web-interface/src/pages/EditExtractorsPage.jsx @@ -42,13 +42,6 @@ const EditExtractorsPage = createReactClass({ mixins: [Reflux.connect(ExtractorsStore), Reflux.connect(InputsStore)], - getInitialState() { - return { - extractor: undefined, - exampleMessage: undefined, - }; - }, - componentDidMount() { const { params } = this.props; From 6f4f74a713447846f202eac56e6dd4196643a5c9 Mon Sep 17 00:00:00 2001 From: Ousmane Samba Date: Thu, 16 Nov 2023 12:35:26 +0100 Subject: [PATCH 4/5] move components to typescrypt --- ...{ExtractorsList.jsx => ExtractorsList.tsx} | 14 +- ...{ExtractorsStore.js => ExtractorsStore.ts} | 130 ++++++++++++++++-- 2 files changed, 126 insertions(+), 18 deletions(-) rename graylog2-web-interface/src/components/extractors/{ExtractorsList.jsx => ExtractorsList.tsx} (89%) rename graylog2-web-interface/src/stores/extractors/{ExtractorsStore.js => ExtractorsStore.ts} (69%) diff --git a/graylog2-web-interface/src/components/extractors/ExtractorsList.jsx b/graylog2-web-interface/src/components/extractors/ExtractorsList.tsx similarity index 89% rename from graylog2-web-interface/src/components/extractors/ExtractorsList.jsx rename to graylog2-web-interface/src/components/extractors/ExtractorsList.tsx index 81d3fab461a1..75fffc83ec23 100644 --- a/graylog2-web-interface/src/components/extractors/ExtractorsList.jsx +++ b/graylog2-web-interface/src/components/extractors/ExtractorsList.tsx @@ -23,16 +23,22 @@ import Spinner from 'components/common/Spinner'; import AddExtractorWizard from 'components/extractors/AddExtractorWizard'; import EntityList from 'components/common/EntityList'; import { ExtractorsActions, ExtractorsStore } from 'stores/extractors/ExtractorsStore'; +import type { ExtractorType, InputSummary, NodeSummary } from 'stores/extractors/ExtractorsStore'; import { useStore } from 'stores/connect'; import ExtractorsListItem from './ExtractorsListItem'; import ExtractorsSortModal from './ExtractorSortModal'; -const fetchExtractors = (inputId) => { - ExtractorsActions.list.triggerPromise(inputId); +type Props = { + input: InputSummary, + node: NodeSummary, }; -const ExtractorsList = ({ input, node }) => { +const fetchExtractors = (inputId: string) => { + ExtractorsActions.list(inputId); +}; + +const ExtractorsList = ({ input, node }: Props) => { const [showSortModal, setShowSortModal] = useState(false); const extractors = useStore(ExtractorsStore, (state) => state.extractors); @@ -40,7 +46,7 @@ const ExtractorsList = ({ input, node }) => { fetchExtractors(input.id); }, [input.id]); - const _formatExtractor = (extractor) => ( + const _formatExtractor = (extractor: ExtractorType) => ( Promise>, + get: (inputId: string, extractorId: string) => Promise, + create: (inputId: string, extractor: ExtractorType, calledFromMethod: boolean) => Promise, + save: (inputId: string, extractor: ExtractorType) => Promise, + update: (inputId: string, extractor: ExtractorType, calledFromMethod: boolean) => Promise, + delete: (inputId: string, extractor: ExtractorType) => Promise, + order: { asyncResult: true }, + import: (inputId: string, orderedExtractors: Array) => Promise, +}; + +export type ExtractorsStoreState = { + extractors: Array, + extractor: ExtractorType, +}; + export const ExtractorsActions = singletonActions( 'core.Extractors', - () => Reflux.createActions({ + () => Reflux.createActions({ list: { asyncResult: true }, get: { asyncResult: true }, create: { asyncResult: true }, @@ -33,11 +135,11 @@ export const ExtractorsActions = singletonActions( update: { asyncResult: true }, delete: { asyncResult: true }, order: { asyncResult: true }, - import: {}, + import: { asyncResult: true }, }), ); -function getExtractorDTO(extractor) { +function getExtractorDTO(extractor: ExtractorType) { const conditionValue = extractor.condition_type && extractor.condition_type !== 'none' ? extractor.condition_value : ''; return { @@ -56,7 +158,7 @@ function getExtractorDTO(extractor) { export const ExtractorsStore = singletonStore( 'core.Extractors', - () => Reflux.createStore({ + () => Reflux.createStore({ listenables: [ExtractorsActions], sourceUrl: '/system/inputs/', extractors: undefined, @@ -81,7 +183,7 @@ export const ExtractorsStore = singletonStore( this.trigger(this.getState()); }, - list(inputId) { + list(inputId: string) { const promise = fetch('GET', URLUtils.qualifyUrl(URLUtils.concatURLPath(this.sourceUrl, inputId, 'extractors'))); promise.then((response) => { @@ -93,7 +195,7 @@ export const ExtractorsStore = singletonStore( }, // Creates an basic extractor object that we can use to create new extractors. - new(type, field) { + new(type: string, field: string) { if (ExtractorUtils.EXTRACTOR_TYPES.indexOf(type) === -1) { throw new Error(`Invalid extractor type provided: ${type}`); } @@ -107,7 +209,7 @@ export const ExtractorsStore = singletonStore( }; }, - get(inputId, extractorId) { + get(inputId: string, extractorId: string) { const promise = fetch('GET', URLUtils.qualifyUrl(URLUtils.concatURLPath(this.sourceUrl, inputId, 'extractors', extractorId))); promise.then((response) => { @@ -118,7 +220,7 @@ export const ExtractorsStore = singletonStore( ExtractorsActions.get.promise(promise); }, - save(inputId, extractor) { + save(inputId: string, extractor: ExtractorType) { let promise; if (extractor.id) { @@ -130,13 +232,13 @@ export const ExtractorsStore = singletonStore( ExtractorsActions.save.promise(promise); }, - _silentExtractorCreate(inputId, extractor) { + _silentExtractorCreate(inputId: string, extractor: ExtractorType) { const url = URLUtils.qualifyUrl(ApiRoutes.ExtractorsController.create(inputId).url); return fetch('POST', url, getExtractorDTO(extractor)); }, - create(inputId, extractor, calledFromMethod) { + create(inputId: string, extractor: ExtractorType, calledFromMethod: boolean) { const promise = this._silentExtractorCreate(inputId, extractor); promise @@ -159,7 +261,7 @@ export const ExtractorsStore = singletonStore( return promise; }, - update(inputId, extractor, calledFromMethod) { + update(inputId: string, extractor: ExtractorType, calledFromMethod: boolean) { const url = URLUtils.qualifyUrl(ApiRoutes.ExtractorsController.update(inputId, extractor.id).url); const promise = fetch('PUT', url, getExtractorDTO(extractor)); @@ -184,7 +286,7 @@ export const ExtractorsStore = singletonStore( return promise; }, - delete(inputId, extractor) { + delete(inputId: string, extractor: ExtractorType) { const url = URLUtils.qualifyUrl(ApiRoutes.ExtractorsController.delete(inputId, extractor.id).url); const promise = fetch('DELETE', url); @@ -205,7 +307,7 @@ export const ExtractorsStore = singletonStore( ExtractorsActions.delete.promise(promise); }, - order(inputId, orderedExtractors) { + order(inputId: string, orderedExtractors: Array) { const url = URLUtils.qualifyUrl(ApiRoutes.ExtractorsController.order(inputId).url); const orderedExtractorsMap = {}; @@ -231,7 +333,7 @@ export const ExtractorsStore = singletonStore( ExtractorsActions.order.promise(promise); }, - import(inputId, extractors) { + import(inputId: string, extractors: Array) { let successfulImports = 0; let failedImports = 0; const promises = []; From b11c881602674c7d28e9fa2d4ffb1e5706b7f089 Mon Sep 17 00:00:00 2001 From: Ousmane Samba Date: Fri, 17 Nov 2023 09:12:59 +0100 Subject: [PATCH 5/5] fix review --- .../src/stores/extractors/ExtractorsStore.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/graylog2-web-interface/src/stores/extractors/ExtractorsStore.ts b/graylog2-web-interface/src/stores/extractors/ExtractorsStore.ts index 247f4139327e..6df5ce8157ed 100644 --- a/graylog2-web-interface/src/stores/extractors/ExtractorsStore.ts +++ b/graylog2-web-interface/src/stores/extractors/ExtractorsStore.ts @@ -69,7 +69,8 @@ type TimerMetricsResponse = { '95th_percentile': number, '99th_percentile': number, '98th_percentile': number, -} +}; + type TimerRateMetricsResponse = { rate: RateMetricsResponse, rate_unit: string, @@ -169,7 +170,7 @@ export const ExtractorsStore = singletonStore( }, init() { - this.trigger({ extractors: this.extractors, extractor: this.extractory }); + this.trigger({ extractors: this.extractors, extractor: this.extractor }); }, getState() {