web-interface.assets.07ba022f-7644.3d54741990922f16b483.js.map Maven / Gradle / Ivy
{"version":3,"file":"07ba022f-7644.3d54741990922f16b483.js","mappings":"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","sources":["webpack://graylog-web-interface/./src/components/extractors/ImportExtractors.jsx","webpack://graylog-web-interface/./src/pages/ImportExtractorsPage.jsx","webpack://graylog-web-interface/./src/routing/withParams.tsx","webpack://graylog-web-interface/./src/stores/extractors/ExtractorsStore.js"],"sourcesContent":["/*\n * Copyright (C) 2020 Graylog, Inc.\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the Server Side Public License, version 1,\n * as published by MongoDB, Inc.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * Server Side Public License for more details.\n *\n * You should have received a copy of the Server Side Public License\n * along with this program. If not, see\n * .\n */\nimport PropTypes from 'prop-types';\nimport React from 'react';\n\nimport { Row, Col, Button, Input } from 'components/bootstrap';\nimport UserNotification from 'util/UserNotification';\nimport { ExtractorsActions } from 'stores/extractors/ExtractorsStore';\n\nclass ImportExtractors extends React.Component {\n static propTypes = {\n input: PropTypes.object.isRequired,\n };\n\n _onSubmit = (event) => {\n event.preventDefault();\n\n try {\n const parsedExtractors = JSON.parse(this.extractorsInput.getValue());\n const { extractors } = parsedExtractors;\n\n ExtractorsActions.import(this.props.input.id, extractors);\n } catch (error) {\n UserNotification.error(`There was an error while parsing extractors. Are they in JSON format? ${error}`,\n 'Could not import extractors');\n }\n };\n\n render() {\n return (\n \n \n \n \n Extractors JSON
\n \n
\n \n \n \n \n
\n \n
\n );\n }\n}\n\nexport default ImportExtractors;\n","/*\n * Copyright (C) 2020 Graylog, Inc.\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the Server Side Public License, version 1,\n * as published by MongoDB, Inc.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * Server Side Public License for more details.\n *\n * You should have received a copy of the Server Side Public License\n * along with this program. If not, see\n * .\n */\nimport PropTypes from 'prop-types';\nimport React from 'react';\nimport createReactClass from 'create-react-class';\nimport Reflux from 'reflux';\n\nimport { DocumentTitle, PageHeader, Spinner } from 'components/common';\nimport ImportExtractors from 'components/extractors/ImportExtractors';\nimport withParams from 'routing/withParams';\nimport { InputsActions, InputsStore } from 'stores/inputs/InputsStore';\n\nconst ImportExtractorsPage = createReactClass({\n displayName: 'ImportExtractorsPage',\n\n propTypes: {\n params: PropTypes.object.isRequired,\n },\n\n mixins: [Reflux.connect(InputsStore)],\n\n componentDidMount() {\n const { params } = this.props;\n\n InputsActions.get.triggerPromise(params.inputId).then((input) => this.setState({ input: input }));\n },\n\n _isLoading() {\n return !this.state.input;\n },\n\n render() {\n if (this._isLoading()) {\n return ;\n }\n\n const { input } = this.state;\n\n return (\n \n \n Import extractors to {input.title}}>\n \n Exported extractors can be imported to an input. All you need is the JSON export of extractors from any\n other Graylog setup or from{' '}\n \n the Graylog Marketplace\n .\n \n \n \n \n \n );\n },\n});\n\nexport default withParams(ImportExtractorsPage);\n","/*\n * Copyright (C) 2020 Graylog, Inc.\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the Server Side Public License, version 1,\n * as published by MongoDB, Inc.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * Server Side Public License for more details.\n *\n * You should have received a copy of the Server Side Public License\n * along with this program. If not, see\n * .\n */\nimport * as React from 'react';\nimport { useParams } from 'react-router-dom';\nimport type { Subtract } from 'utility-types';\n\ntype ParamsContext = {\n params: {\n [key: string]: string | null | undefined;\n };\n};\n\nconst withParams = (Component: React.ComponentType): React.ComponentType> => (props) => {\n const params = useParams();\n\n return ;\n};\n\nexport default withParams;\n","/*\n * Copyright (C) 2020 Graylog, Inc.\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the Server Side Public License, version 1,\n * as published by MongoDB, Inc.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * Server Side Public License for more details.\n *\n * You should have received a copy of the Server Side Public License\n * along with this program. If not, see\n * .\n */\nimport Reflux from 'reflux';\n\nimport ApiRoutes from 'routing/ApiRoutes';\nimport fetch from 'logic/rest/FetchProvider';\nimport ExtractorUtils from 'util/ExtractorUtils';\nimport * as URLUtils from 'util/URLUtils';\nimport UserNotification from 'util/UserNotification';\nimport { singletonStore, singletonActions } from 'logic/singleton';\n\nexport const ExtractorsActions = singletonActions(\n 'core.Extractors',\n () => Reflux.createActions({\n list: { asyncResult: true },\n get: { asyncResult: true },\n create: { asyncResult: true },\n save: { asyncResult: true },\n update: { asyncResult: true },\n delete: { asyncResult: true },\n order: { asyncResult: true },\n import: {},\n }),\n);\n\nfunction getExtractorDTO(extractor) {\n const conditionValue = extractor.condition_type && extractor.condition_type !== 'none' ? extractor.condition_value : '';\n\n return {\n title: extractor.title,\n cursor_strategy: extractor.cursor_strategy || 'copy',\n source_field: extractor.source_field,\n target_field: extractor.target_field,\n extractor_type: extractor.type || extractor.extractor_type, // \"extractor_type\" needed for imports\n extractor_config: extractor.extractor_config,\n converters: extractor.converters,\n condition_type: extractor.condition_type || 'none',\n condition_value: conditionValue,\n order: extractor.order,\n };\n}\n\nexport const ExtractorsStore = singletonStore(\n 'core.Extractors',\n () => Reflux.createStore({\n listenables: [ExtractorsActions],\n sourceUrl: '/system/inputs/',\n extractors: undefined,\n extractor: undefined,\n\n init() {\n this.trigger({ extractors: this.extractors, extractor: this.extractor });\n },\n\n list(inputId) {\n const promise = fetch('GET', URLUtils.qualifyUrl(URLUtils.concatURLPath(this.sourceUrl, inputId, 'extractors')));\n\n promise.then((response) => {\n this.extractors = response.extractors;\n this.trigger({ extractors: this.extractors });\n });\n\n ExtractorsActions.list.promise(promise);\n },\n\n // Creates an basic extractor object that we can use to create new extractors.\n new(type, field) {\n if (ExtractorUtils.EXTRACTOR_TYPES.indexOf(type) === -1) {\n throw new Error(`Invalid extractor type provided: ${type}`);\n }\n\n return {\n type: type,\n source_field: field,\n converters: [],\n extractor_config: {},\n target_field: '',\n };\n },\n\n get(inputId, extractorId) {\n const promise = fetch('GET', URLUtils.qualifyUrl(URLUtils.concatURLPath(this.sourceUrl, inputId, 'extractors', extractorId)));\n\n promise.then((response) => {\n this.extractor = response;\n this.trigger({ extractor: this.extractor });\n });\n\n ExtractorsActions.get.promise(promise);\n },\n\n save(inputId, extractor) {\n let promise;\n\n if (extractor.id) {\n promise = this.update(inputId, extractor, true);\n } else {\n promise = this.create(inputId, extractor, true);\n }\n\n ExtractorsActions.save.promise(promise);\n },\n\n _silentExtractorCreate(inputId, extractor) {\n const url = URLUtils.qualifyUrl(ApiRoutes.ExtractorsController.create(inputId).url);\n\n return fetch('POST', url, getExtractorDTO(extractor));\n },\n\n create(inputId, extractor, calledFromMethod) {\n const promise = this._silentExtractorCreate(inputId, extractor);\n\n promise\n .then(() => {\n UserNotification.success(`Extractor ${extractor.title} created successfully`);\n\n if (this.extractor) {\n ExtractorsActions.get.triggerPromise(inputId, extractor.id);\n }\n })\n .catch((error) => {\n UserNotification.error(`Creating extractor failed: ${error}`,\n 'Could not create extractor');\n });\n\n if (!calledFromMethod) {\n ExtractorsActions.create.promise(promise);\n }\n\n return promise;\n },\n\n update(inputId, extractor, calledFromMethod) {\n const url = URLUtils.qualifyUrl(ApiRoutes.ExtractorsController.update(inputId, extractor.id).url);\n\n const promise = fetch('PUT', url, getExtractorDTO(extractor));\n\n promise\n .then(() => {\n UserNotification.success(`Extractor \"${extractor.title}\" updated successfully`);\n\n if (this.extractor) {\n ExtractorsActions.get.triggerPromise(inputId, extractor.id);\n }\n })\n .catch((error) => {\n UserNotification.error(`Updating extractor failed: ${error}`,\n 'Could not update extractor');\n });\n\n if (!calledFromMethod) {\n ExtractorsActions.update.promise(promise);\n }\n\n return promise;\n },\n\n delete(inputId, extractor) {\n const url = URLUtils.qualifyUrl(ApiRoutes.ExtractorsController.delete(inputId, extractor.id).url);\n\n const promise = fetch('DELETE', url);\n\n promise\n .then(() => {\n UserNotification.success(`Extractor \"${extractor.title}\" deleted successfully`);\n\n if (this.extractors) {\n ExtractorsActions.list.triggerPromise(inputId);\n }\n })\n .catch((error) => {\n UserNotification.error(`Deleting extractor failed: ${error}`,\n `Could not delete extractor ${extractor.title}`);\n });\n\n ExtractorsActions.delete.promise(promise);\n },\n\n order(inputId, orderedExtractors) {\n const url = URLUtils.qualifyUrl(ApiRoutes.ExtractorsController.order(inputId).url);\n const orderedExtractorsMap = {};\n\n orderedExtractors.forEach((extractor, idx) => {\n orderedExtractorsMap[idx] = extractor.id;\n });\n\n const promise = fetch('POST', url, { order: orderedExtractorsMap });\n\n promise.then(() => {\n UserNotification.success('Extractor positions updated successfully');\n\n if (this.extractors) {\n ExtractorsActions.list.triggerPromise(inputId);\n }\n });\n\n promise.catch((error) => {\n UserNotification.error(`Changing extractor positions failed: ${error}`,\n 'Could not update extractor positions');\n });\n\n ExtractorsActions.order.promise(promise);\n },\n\n import(inputId, extractors) {\n let successfulImports = 0;\n let failedImports = 0;\n const promises = [];\n\n extractors.forEach((extractor) => {\n const promise = this._silentExtractorCreate(inputId, extractor);\n\n promise\n .then(() => { successfulImports += 1; })\n .catch(() => { failedImports += 1; });\n\n promises.push(promise);\n });\n\n Promise.allSettled(promises).then(() => {\n if (failedImports === 0) {\n UserNotification.success(`Import results: ${successfulImports} extractor(s) imported.`,\n 'Import operation successful');\n } else {\n UserNotification.warning(`Import results: ${successfulImports} extractor(s) imported, ${failedImports} error(s).`,\n 'Import operation completed');\n }\n });\n },\n }),\n);\n"],"names":["ImportExtractors","event","parsedExtractors","extractors","error","UserNotification","extractorsInput","ImportExtractorsPage","InputsStore","params","input","withParams","Component","props","ExtractorsActions","getExtractorDTO","extractor","conditionValue","ExtractorsStore","inputId","promise","response","type","field","extractorId","url","calledFromMethod","orderedExtractors","orderedExtractorsMap","idx","successfulImports","failedImports","promises"],"sourceRoot":""}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy